diff --git a/.env b/.env
index 9b549a6b69..c8c0fccb2b 100644
--- a/.env
+++ b/.env
@@ -4,6 +4,7 @@ _APP_WORKER_PER_CORE=6
_APP_CONSOLE_WHITELIST_ROOT=disabled
_APP_CONSOLE_WHITELIST_EMAILS=
_APP_CONSOLE_WHITELIST_IPS=
+_APP_CONSOLE_COUNTRIES_DENYLIST=AQ
_APP_CONSOLE_HOSTNAMES=localhost,appwrite.io,*.appwrite.io
_APP_SYSTEM_EMAIL_NAME=Appwrite
_APP_SYSTEM_EMAIL_ADDRESS=team@appwrite.io
@@ -51,10 +52,6 @@ _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=
@@ -80,7 +77,7 @@ _APP_MAINTENANCE_RETENTION_CACHE=2592000
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
_APP_MAINTENANCE_RETENTION_ABUSE=86400
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
-_APP_USAGE_AGGREGATION_INTERVAL=5
+_APP_USAGE_AGGREGATION_INTERVAL=60000
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
_APP_USAGE_STATS=enabled
@@ -103,3 +100,4 @@ _APP_ASSISTANT_OPENAI_API_KEY=
_APP_MESSAGE_SMS_TEST_DSN=
_APP_MESSAGE_EMAIL_TEST_DSN=
_APP_MESSAGE_PUSH_TEST_DSN=
+_APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 0c2321bcfa..ad08c2d4e3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
[submodule "app/console"]
path = app/console
url = https://github.com/appwrite/console
- branch = 3.2.16
+ branch = feat-mfa
diff --git a/CHANGES.md b/CHANGES.md
index 5634340d69..5dd4ba8770 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,14 @@
+# Version 1.4.14
+
+## Changes
+- New usage metrics collection flow [#7005](https://github.com/appwrite/appwrite/pull/7005)
+ - 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.
+ - updated Metric names.
+
# Version 1.4.13
## Notable changes
@@ -49,6 +60,7 @@
* Use getQueueSize() in the Health service's get X queue endpoints [#7073](https://github.com/appwrite/appwrite/pull/7073)
* Delete linked VCS repos and comments [#7066](https://github.com/appwrite/appwrite/pull/7066)
+
# Version 1.4.9
## Bug fixes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ccd61e742b..529f6103d1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -210,7 +210,6 @@ Appwrite's current structure is a combination of both [Monolithic](https://en.wi
│ ├── Task
│ ├── Template
│ ├── URL
-│ ├── Usage
│ └── Utopia
└── tests # End to end & unit tests
├── e2e
@@ -345,13 +344,13 @@ Things to remember when releasing SDKs:
## Debug
-Appwrite uses [yasd](https://github.com/swoole/yasd) debugger, which can be made available during build of Appwrite. You can connect to the debugger using VS Code's [PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) extension.
+Appwrite uses [XDebug](https://github.com/xdebug/xdebug) debugger, which can be made available during build of Appwrite. You can connect to the debugger using VS Code's [PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) extension.
If you are in PHP Storm you don't need any plugin. Below are the settings required for remote debugger connection:
-1. Create an init file.
-2. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php**.
-3. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
+1. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
+2. If needed edit the **dev/xdebug.ini** file to your needs.
+3. Launch your Appwrite instance while your debugger is listening for connections.
### VS Code Launch Configuration
diff --git a/Dockerfile b/Dockerfile
index 19013ab0a0..968b0bb22a 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.3 as final
+FROM appwrite/base:0.7.2 as final
LABEL maintainer="team@appwrite.io"
@@ -56,6 +56,7 @@ COPY ./public /usr/src/code/public
COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs
COPY ./src /usr/src/code/src
+COPY ./dev /usr/src/code/dev
# Set Volumes
RUN mkdir -p /storage/uploads && \
@@ -87,7 +88,6 @@ RUN chmod +x /usr/local/bin/doctor && \
chmod +x /usr/local/bin/ssl && \
chmod +x /usr/local/bin/test && \
chmod +x /usr/local/bin/upgrade && \
- chmod +x /usr/local/bin/usage && \
chmod +x /usr/local/bin/vars && \
chmod +x /usr/local/bin/worker-audits && \
chmod +x /usr/local/bin/worker-builds && \
@@ -99,7 +99,10 @@ 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-migrations && \
- chmod +x /usr/local/bin/worker-webhooks
+ chmod +x /usr/local/bin/worker-webhooks && \
+ chmod +x /usr/local/bin/worker-hamster && \
+ chmod +x /usr/local/bin/worker-usage
+
# Cloud Executabless
RUN chmod +x /usr/local/bin/calc-tier-stats && \
@@ -111,15 +114,23 @@ RUN chmod +x /usr/local/bin/calc-tier-stats && \
chmod +x /usr/local/bin/patch-delete-project-collections && \
chmod +x /usr/local/bin/patch-delete-schedule-updated-at-attribute && \
chmod +x /usr/local/bin/patch-recreate-repositories-documents && \
- chmod +x /usr/local/bin/volume-sync
+ chmod +x /usr/local/bin/volume-sync && \
+ chmod +x /usr/local/bin/patch-delete-project-collections && \
+ chmod +x /usr/local/bin/delete-orphaned-projects && \
+ 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/get-migration-stats && \
+ chmod +x /usr/local/bin/create-inf-metric
# Letsencrypt Permissions
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
-RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/src/code/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi
-
+RUN if [ "$DEBUG" == "true" ]; then cp /usr/src/code/dev/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini; fi
RUN if [ "$DEBUG" == "true" ]; then echo "opcache.enable=0" >> /usr/local/etc/php/conf.d/appwrite.ini; fi
+RUN if [ "$DEBUG" = "false" ]; then rm -rf /usr/src/code/dev; fi
+RUN if [ "$DEBUG" = "false" ]; then rm -f /usr/local/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so; fi
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/appwrite.ini
diff --git a/app/cli.php b/app/cli.php
index 003f3a1f79..668b70d8b7 100644
--- a/app/cli.php
+++ b/app/cli.php
@@ -72,7 +72,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->getDatabase(), $last))) { /** TODO cache ready variable using registry */
throw new Exception('Tables not ready yet.');
}
@@ -125,30 +125,6 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
};
}, ['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('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
}, ['pools']);
diff --git a/app/config/auth.php b/app/config/auth.php
index ca62256dc2..2330fe75cf 100644
--- a/app/config/auth.php
+++ b/app/config/auth.php
@@ -17,6 +17,13 @@ return [
'docs' => 'https://appwrite.io/docs/references/cloud/client-web/account#accountCreateMagicURLToken',
'enabled' => true,
],
+ 'email-otp' => [
+ 'name' => 'Email (OTP)',
+ 'key' => 'emailOtp',
+ 'icon' => '/images/users/email.png',
+ 'docs' => 'https://appwrite.io/docs/references/cloud/client-web/account#accountCreateEmailToken',
+ 'enabled' => true,
+ ],
'anonymous' => [
'name' => 'Anonymous',
'key' => 'anonymous',
diff --git a/app/config/collections.php b/app/config/collections.php
index 526ed9f954..bd379b0cce 100644
--- a/app/config/collections.php
+++ b/app/config/collections.php
@@ -18,6 +18,63 @@ $auth = Config::getParam('auth', []);
*/
$commonCollections = [
+ 'cache' => [
+ '$collection' => Database::METADATA,
+ '$id' => 'cache',
+ 'name' => 'Cache',
+ 'attributes' => [
+ [
+ '$id' => 'resource',
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 255,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => 'accessedAt',
+ 'type' => Database::VAR_DATETIME,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => false,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['datetime'],
+ ],
+ [
+ '$id' => 'signature',
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 255,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ ],
+ 'indexes' => [
+ [
+ '$id' => '_key_accessedAt',
+ 'type' => Database::INDEX_KEY,
+ 'attributes' => ['accessedAt'],
+ 'lengths' => [],
+ 'orders' => [],
+ ],
+ [
+ '$id' => '_key_resource',
+ 'type' => Database::INDEX_KEY,
+ 'attributes' => ['resource'],
+ 'lengths' => [],
+ 'orders' => [],
+ ],
+ ],
+ ],
+
'users' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('users'),
@@ -188,6 +245,61 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('mfa'),
+ 'type' => Database::VAR_BOOLEAN,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('totp'),
+ 'type' => Database::VAR_BOOLEAN,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('totpVerification'),
+ 'type' => Database::VAR_BOOLEAN,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('totpSecret'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 256,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('totpBackup'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 6,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => true,
+ 'filters' => [],
+ ],
[
'$id' => ID::custom('sessions'),
'type' => Database::VAR_STRING,
@@ -210,6 +322,17 @@ $commonCollections = [
'array' => false,
'filters' => ['subQueryTokens'],
],
+ [
+ '$id' => ID::custom('challenges'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 16384,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['subQueryChallenges'],
+ ],
[
'$id' => ID::custom('memberships'),
'type' => Database::VAR_STRING,
@@ -423,6 +546,87 @@ $commonCollections = [
],
],
+ 'challenges' => [
+ '$collection' => ID::custom(Database::METADATA),
+ '$id' => ID::custom('challenges'),
+ 'name' => 'Challenges',
+ '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' => Database::LENGTH_KEY,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('token'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 512, // https://www.tutorialspoint.com/how-long-is-the-sha256-hash-in-mysql (512 for encryption)
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['encrypt'],
+ ], [
+ '$id' => ID::custom('code'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 512,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['encrypt'],
+ ], [
+ '$id' => ID::custom('expire'),
+ 'type' => Database::VAR_DATETIME,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => false,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['datetime'],
+ ]
+ ],
+ 'indexes' => [
+ [
+ '$id' => ID::custom('_key_user'),
+ 'type' => Database::INDEX_KEY,
+ 'attributes' => ['userInternalId'],
+ 'lengths' => [Database::LENGTH_KEY],
+ 'orders' => [Database::ORDER_ASC],
+ ]
+ ],
+ ],
+
'sessions' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('sessions'),
@@ -681,6 +885,28 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('factors'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => 256,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => new \stdClass(),
+ 'array' => true,
+ 'filters' => ['json'],
+ ],
+ [
+ '$id' => ID::custom('expire'),
+ 'type' => Database::VAR_DATETIME,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => false,
+ 'required' => true,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => ['datetime'],
+ ],
],
'indexes' => [
[
@@ -1281,10 +1507,10 @@ $commonCollections = [
]
],
- 'stats' => [
+ 'stats_v2' => [
'$collection' => ID::custom(Database::METADATA),
- '$id' => ID::custom('stats'),
- 'name' => 'Stats',
+ '$id' => ID::custom('stats_v2'),
+ 'name' => 'stats_v2',
'attributes' => [
[
'$id' => ID::custom('metric'),
@@ -1313,7 +1539,7 @@ $commonCollections = [
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 8,
- 'signed' => false,
+ 'signed' => true,
'required' => true,
'default' => null,
'array' => false,
@@ -1341,17 +1567,6 @@ $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' => [
[
@@ -1370,7 +1585,7 @@ $commonCollections = [
],
[
'$id' => ID::custom('_key_metric_period_time'),
- 'type' => Database::INDEX_KEY,
+ 'type' => Database::INDEX_UNIQUE,
'attributes' => ['metric', 'period', 'time'],
'lengths' => [],
'orders' => [Database::ORDER_DESC],
@@ -1516,17 +1731,6 @@ $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,
@@ -1687,17 +1891,6 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
- [
- '$id' => ID::custom('description'),
- 'type' => Database::VAR_STRING,
- 'format' => '',
- 'size' => 2048,
- 'signed' => true,
- 'required' => false,
- 'default' => null,
- 'array' => false,
- 'filters' => [],
- ],
[
'$id' => ID::custom('total'),
'type' => Database::VAR_INTEGER,
@@ -1924,6 +2117,28 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('sessionId'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => Database::LENGTH_KEY,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
+ [
+ '$id' => ID::custom('sessionInternalId'),
+ 'type' => Database::VAR_STRING,
+ 'format' => '',
+ 'size' => Database::LENGTH_KEY,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => null,
+ 'array' => false,
+ 'filters' => [],
+ ],
[
'$id' => ID::custom('providerType'),
'type' => Database::VAR_STRING,
@@ -1979,6 +2194,17 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
+ [
+ '$id' => ID::custom('expired'),
+ 'type' => Database::VAR_BOOLEAN,
+ 'format' => '',
+ 'size' => 0,
+ 'signed' => true,
+ 'required' => false,
+ 'default' => false,
+ 'array' => false,
+ 'filters' => [],
+ ],
],
'indexes' => [
[
@@ -3535,63 +3761,6 @@ $projectCollections = array_merge([
],
],
- 'cache' => [
- '$collection' => Database::METADATA,
- '$id' => 'cache',
- 'name' => 'Cache',
- 'attributes' => [
- [
- '$id' => 'resource',
- 'type' => Database::VAR_STRING,
- 'format' => '',
- 'size' => 255,
- 'signed' => true,
- 'required' => false,
- 'default' => null,
- 'array' => false,
- 'filters' => [],
- ],
- [
- '$id' => 'accessedAt',
- 'type' => Database::VAR_DATETIME,
- 'format' => '',
- 'size' => 0,
- 'signed' => false,
- 'required' => false,
- 'default' => null,
- 'array' => false,
- 'filters' => ['datetime'],
- ],
- [
- '$id' => 'signature',
- 'type' => Database::VAR_STRING,
- 'format' => '',
- 'size' => 255,
- 'signed' => true,
- 'required' => false,
- 'default' => null,
- 'array' => false,
- 'filters' => [],
- ],
- ],
- 'indexes' => [
- [
- '$id' => '_key_accessedAt',
- 'type' => Database::INDEX_KEY,
- 'attributes' => ['accessedAt'],
- 'lengths' => [],
- 'orders' => [],
- ],
- [
- '$id' => '_key_resource',
- 'type' => Database::INDEX_KEY,
- 'attributes' => ['resource'],
- 'lengths' => [],
- 'orders' => [],
- ],
- ],
- ],
-
'variables' => [
'$collection' => Database::METADATA,
'$id' => 'variables',
diff --git a/app/config/errors.php b/app/config/errors.php
index e5c2d4e5bd..79a092ec99 100644
--- a/app/config/errors.php
+++ b/app/config/errors.php
@@ -4,8 +4,8 @@
* List of server wide error codes and their respective messages.
*/
-use Appwrite\Enum\MessageStatus;
use Appwrite\Extend\Exception;
+use Appwrite\Messaging\Status as MessageStatus;
return [
/** General Errors */
@@ -114,6 +114,11 @@ return [
'description' => 'Value must be a valid phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.',
'code' => 400,
],
+ Exception::GENERAL_REGION_ACCESS_DENIED => [
+ 'name' => Exception::GENERAL_REGION_ACCESS_DENIED,
+ 'description' => 'Your location is not supported due to legal requirements.',
+ 'code' => 451,
+ ],
/** User Errors */
Exception::USER_COUNT_EXCEEDED => [
@@ -237,6 +242,11 @@ return [
'description' => 'Missing ID from OAuth2 provider.',
'code' => 400,
],
+ Exception::USER_MORE_FACTORS_REQUIRED => [
+ 'name' => Exception::USER_MORE_FACTORS_REQUIRED,
+ 'description' => 'More factors are required to complete the sign in process.',
+ 'code' => 400,
+ ],
Exception::USER_OAUTH2_BAD_REQUEST => [
'name' => Exception::USER_OAUTH2_BAD_REQUEST,
'description' => 'OAuth2 provider rejected the bad request.',
@@ -811,6 +821,11 @@ return [
'description' => 'Provider with the requested ID is of the incorrect type.',
'code' => 400,
],
+ Exception::PROVIDER_MISSING_CREDENTIALS => [
+ 'name' => Exception::PROVIDER_MISSING_CREDENTIALS,
+ 'description' => 'Provider with the requested ID is missing credentials.',
+ 'code' => 400,
+ ],
/** Topics */
Exception::TOPIC_NOT_FOUND => [
diff --git a/app/config/locale/languages.php b/app/config/locale/languages.php
index 6272bd02a6..eeea92e636 100644
--- a/app/config/locale/languages.php
+++ b/app/config/locale/languages.php
@@ -654,10 +654,15 @@ return [
"nativeName" => "پښتو"
],
[
- "code" => "pt",
+ "code" => "pt-pt",
"name" => "Portuguese",
"nativeName" => "Português"
],
+ [
+ "code" => "pt-br",
+ "name" => "Portuguese (Brazilian)",
+ "nativeName" => "Português"
+ ],
[
"code" => "qu",
"name" => "Quechua",
@@ -919,9 +924,14 @@ return [
"nativeName" => "Cuengh / Tôô / 壮语"
],
[
- "code" => "zh",
- "name" => "Chinese",
- "nativeName" => "中文"
+ "code" => "zh-cn",
+ "name" => "Chinese (Simplified)",
+ "nativeName" => "中国人"
+ ],
+ [
+ "code" => "zh-tw",
+ "name" => "Chinese (Traditional)",
+ "nativeName" => "中國人"
],
[
"code" => "zu",
diff --git a/app/config/locale/templates/email-base-styled.tpl b/app/config/locale/templates/email-base-styled.tpl
index 8e8bc7f6cd..4d6972389e 100644
--- a/app/config/locale/templates/email-base-styled.tpl
+++ b/app/config/locale/templates/email-base-styled.tpl
@@ -1,10 +1,9 @@
-
+
-
+
+
+
+
-
+
+
|
@@ -176,7 +142,9 @@
- | {{message}} |
+
+{{body}}
+ |
@@ -200,7 +168,7 @@
class="social-icon"
title="Twitter"
>
-
+
@@ -208,7 +176,7 @@
href="https://appwrite.io/discord"
class="social-icon"
>
-
+
|
@@ -216,7 +184,7 @@
href="https://github.com/appwrite/appwrite"
class="social-icon"
>
-
+
|
diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl
index 346f2f1589..13056fd5ae 100644
--- a/app/config/locale/templates/email-base.tpl
+++ b/app/config/locale/templates/email-base.tpl
@@ -1,5 +1,74 @@
+
+
+
+
+
+
@@ -10,6 +79,7 @@