diff --git a/.env b/.env index 9df5864bd0..0b5ddf24c6 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= @@ -62,6 +59,7 @@ _APP_SMTP_USERNAME= _APP_SMTP_PASSWORD= _APP_SMS_PROVIDER=sms://username:password@mock _APP_SMS_FROM=+123456789 +_APP_SMS_PROJECTS_DENY_LIST= _APP_STORAGE_LIMIT=30000000 _APP_STORAGE_PREVIEW_LIMIT=20000000 _APP_FUNCTIONS_SIZE_LIMIT=30000000 @@ -76,11 +74,12 @@ _APP_EXECUTOR_SECRET=your-secret-key _APP_EXECUTOR_HOST=http://proxy/v1 _APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1 _APP_MAINTENANCE_INTERVAL=86400 +_APP_MAINTENANCE_DELAY= _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 @@ -88,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= @@ -99,4 +98,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_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/.github/workflows/tests.yml b/.github/workflows/tests.yml index 842d61ff1c..9c9b678302 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,8 +75,32 @@ jobs: - name: Run Unit Tests run: docker compose exec appwrite test /usr/src/code/tests/unit - e2e_test: - name: E2E Test + e2e_general_test: + name: E2E General Test + runs-on: ubuntu-latest + needs: setup + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: Load Cache + uses: actions/cache@v3 + with: + key: ${{ env.CACHE_KEY }} + path: /tmp/${{ env.IMAGE }}.tar + fail-on-cache-miss: true + + - name: Load and Start Appwrite + run: | + docker load --input /tmp/${{ env.IMAGE }}.tar + docker compose up -d + sleep 10 + + - name: Run General Tests + run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/General --debug + + e2e_service_test: + name: E2E Service Test runs-on: ubuntu-latest needs: setup strategy: @@ -99,6 +123,7 @@ jobs: Users, Webhooks, VCS, + Messaging, ] steps: @@ -119,4 +144,4 @@ jobs: sleep 10 - name: Run ${{matrix.service}} Tests - run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug \ No newline at end of file + run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug 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/.gitmodules b/.gitmodules index 0c2321bcfa..bed812bea0 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 = chore-update-sdk diff --git a/CHANGES.md b/CHANGES.md index 83e09896c8..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 @@ -484,7 +496,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/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 2f85f2cc43..1075f9a12a 100755 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ --no-plugins --no-scripts --prefer-dist \ `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi` -FROM --platform=$BUILDPLATFORM node:16.14.2-alpine3.15 as node +FROM --platform=$BUILDPLATFORM node:20.11.0-alpine3.19 as node COPY app/console /usr/local/src/console @@ -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.8.0 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 && \ @@ -71,51 +72,69 @@ RUN mkdir -p /storage/uploads && \ chown -Rf www-data.www-data /storage/functions && chmod -Rf 0755 /storage/functions && \ chown -Rf www-data.www-data /storage/debug && chmod -Rf 0755 /storage/debug +# Development Executables +RUN chmod +x /usr/local/bin/dev-generate-translations + # Executables RUN chmod +x /usr/local/bin/doctor && \ - chmod +x /usr/local/bin/maintenance && \ - chmod +x /usr/local/bin/usage && \ chmod +x /usr/local/bin/install && \ - chmod +x /usr/local/bin/upgrade && \ + chmod +x /usr/local/bin/maintenance && \ chmod +x /usr/local/bin/migrate && \ chmod +x /usr/local/bin/realtime && \ - chmod +x /usr/local/bin/schedule && \ + chmod +x /usr/local/bin/schedule-functions && \ + chmod +x /usr/local/bin/schedule-messages && \ chmod +x /usr/local/bin/sdks && \ chmod +x /usr/local/bin/specs && \ chmod +x /usr/local/bin/ssl && \ chmod +x /usr/local/bin/test && \ + chmod +x /usr/local/bin/upgrade && \ chmod +x /usr/local/bin/vars && \ + chmod +x /usr/local/bin/queue-retry && \ + chmod +x /usr/local/bin/queue-count-failed && \ + chmod +x /usr/local/bin/queue-count-processing && \ + chmod +x /usr/local/bin/queue-count-success && \ chmod +x /usr/local/bin/worker-audits && \ + chmod +x /usr/local/bin/worker-builds && \ chmod +x /usr/local/bin/worker-certificates && \ chmod +x /usr/local/bin/worker-databases && \ chmod +x /usr/local/bin/worker-deletes && \ chmod +x /usr/local/bin/worker-functions && \ - chmod +x /usr/local/bin/worker-builds && \ + chmod +x /usr/local/bin/worker-hamster && \ 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-migrations && \ - chmod +x /usr/local/bin/worker-hamster + 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/hamster && \ - chmod +x /usr/local/bin/volume-sync && \ +RUN chmod +x /usr/local/bin/calc-tier-stats && \ + chmod +x /usr/local/bin/calc-users-stats && \ + chmod +x /usr/local/bin/clear-card-cache && \ + chmod +x /usr/local/bin/delete-orphaned-projects && \ + chmod +x /usr/local/bin/get-migration-stats && \ + chmod +x /usr/local/bin/hamster && \ + 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/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/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/assets/dbip/dbip-country-lite-2023-01.mmdb b/app/assets/dbip/dbip-country-lite-2023-01.mmdb deleted file mode 100644 index dd98483fe5..0000000000 Binary files a/app/assets/dbip/dbip-country-lite-2023-01.mmdb and /dev/null differ diff --git a/app/assets/dbip/dbip-country-lite-2024-02.mmdb b/app/assets/dbip/dbip-country-lite-2024-02.mmdb new file mode 100644 index 0000000000..e02ba8af04 Binary files /dev/null and b/app/assets/dbip/dbip-country-lite-2024-02.mmdb differ diff --git a/app/cli.php b/app/cli.php index 003f3a1f79..559378bc57 100644 --- a/app/cli.php +++ b/app/cli.php @@ -72,12 +72,12 @@ 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.'); } $ready = true; - } catch (\Exception $err) { + } catch (\Throwable $err) { Console::warning($err->getMessage()); $pools->get('console')->reclaim(); sleep($sleep); @@ -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 cf1d180aaa..2330fe75cf 100644 --- a/app/config/auth.php +++ b/app/config/auth.php @@ -7,21 +7,28 @@ return [ 'name' => 'Email/Password', 'key' => 'emailPassword', 'icon' => '/images/users/email.png', - 'docs' => 'https://appwrite.io/docs/client/account?sdk=web-default#accountCreateEmailSession', + 'docs' => 'https://appwrite.io/docs/references/cloud/client-web/account#accountCreateEmailPasswordSession', 'enabled' => true, ], 'magic-url' => [ 'name' => 'Magic URL', 'key' => 'usersAuthMagicURL', 'icon' => '/images/users/magic-url.png', - 'docs' => 'https://appwrite.io/docs/client/account?sdk=web-default#accountCreateMagicURLSession', + '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', 'icon' => '/images/users/anonymous.png', - 'docs' => 'https://appwrite.io/docs/client/account?sdk=web-default#accountCreateAnonymousSession', + 'docs' => 'https://appwrite.io/docs/references/cloud/client-web/account#accountCreateAnonymousSession', 'enabled' => true, ], 'invites' => [ @@ -42,7 +49,7 @@ return [ 'name' => 'Phone', 'key' => 'phone', 'icon' => '/images/users/phone.png', - 'docs' => 'https://appwrite.io/docs/client/account?sdk=web-default#accountCreatePhoneSession', + 'docs' => 'https://appwrite.io/docs/references/cloud/client-web/account#accountCreatePhoneToken', 'enabled' => true, ], ]; diff --git a/app/config/collections.php b/app/config/collections.php index db229ce87a..e8a24c910e 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('oAuthProviders', []); $auth = Config::getParam('auth', []); /** @@ -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, @@ -221,6 +344,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, @@ -412,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'), @@ -670,6 +885,28 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('factors'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 256, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('expire'), + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], ], 'indexes' => [ [ @@ -1302,7 +1539,7 @@ $commonCollections = [ 'type' => Database::VAR_INTEGER, 'format' => '', 'size' => 8, - 'signed' => false, + 'signed' => true, 'required' => true, 'default' => null, 'array' => false, @@ -1330,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' => [ [ @@ -1359,14 +1585,699 @@ $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], ], ], ], - ]; + + 'providers' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('providers'), + 'name' => 'Providers', + 'attributes' => [ + [ + '$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('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, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['json', 'encrypt'], + ], + [ + '$id' => ID::custom('options'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => false, + 'filters' => ['json'], + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 65535, + 'signed' => true, + 'required' => false, + 'default' => '', + 'array' => false, + 'filters' => ['providerSearch'], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_provider'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['provider'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_name'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['name'], + '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_enabled_type'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['enabled', 'type'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], + ] + ], + ], + + 'messages' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$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('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, + 'format' => '', + 'size' => 65535, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => ['json'], + ], + [ + '$id' => ID::custom('topics'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 21845, + 'signed' => true, + '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' => [], + ], + [ + '$id' => ID::custom('scheduledAt'), + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], + [ + '$id' => ID::custom('scheduleInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('scheduleId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$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, + 'format' => '', + 'size' => 65535, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('deliveredTotal'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => '', + 'array' => false, + 'filters' => ['messageSearch'], + ], + ], + 'indexes' => [ + [ + '$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('name'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('subscribe'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('emailTotal'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('smsTotal'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('pushTotal'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('targets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['subQueryTopicTargets'], + ], + [ + '$id' => ID::custom('search'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => '', + 'array' => false, + 'filters' => ['topicSearch'], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_name'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['name'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ] + ], + ], + + 'subscribers' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('subscribers'), + 'name' => 'Subscribers', + 'attributes' => [ + [ + '$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('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, + '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' => [], + ], + [ + '$id' => ID::custom('providerType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => true, + 'default' => null, + '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_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_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_topicId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['topicId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_topicInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['topicInternalId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_fulltext_search'), + 'type' => Database::INDEX_FULLTEXT, + 'attributes' => ['search'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], + + 'targets' => [ + '$collection' => ID::custom(DATABASE::METADATA), + '$id' => ID::custom('targets'), + 'name' => 'Targets', + '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('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, + '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' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('providerInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('identifier'), + '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' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('expired'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => false, + 'array' => false, + 'filters' => [], + ], + ], + 'indexes' => [ + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [], + '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_identifier'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['identifier'], + 'lengths' => [], + 'orders' => [], + ], + ], + ], +]; $projectCollections = array_merge([ 'databases' => [ @@ -2883,63 +3794,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', @@ -3412,7 +4266,7 @@ $consoleCollections = array_merge([ 'filters' => ['json'], ], [ - '$id' => ID::custom('authProviders'), + '$id' => ID::custom('oAuthProviders'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 16384, @@ -3508,6 +4362,17 @@ $consoleCollections = array_merge([ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('resourceCollection'), + '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, @@ -3914,6 +4779,39 @@ $consoleCollections = array_merge([ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('enabled'), + 'type' => Database::VAR_BOOLEAN, + 'signed' => true, + 'size' => 0, + 'format' => '', + 'filters' => [], + 'required' => false, + 'default' => true, + 'array' => false, + ], + [ + '$id' => ID::custom('logs'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 1000000, + 'signed' => true, + 'required' => false, + 'default' => '', + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('attempts'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ diff --git a/app/config/errors.php b/app/config/errors.php index c0628920d9..3f12b5953a 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -5,6 +5,7 @@ */ use Appwrite\Extend\Exception; +use Appwrite\Messaging\Status as MessageStatus; return [ /** General Errors */ @@ -103,6 +104,21 @@ 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, + ], + 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 => [ @@ -226,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' => 401, + ], Exception::USER_OAUTH2_BAD_REQUEST => [ 'name' => Exception::USER_OAUTH2_BAD_REQUEST, 'description' => 'OAuth2 provider rejected the bad request.', @@ -251,6 +272,16 @@ return [ 'description' => 'User phone is already verified', 'code' => 409 ], + Exception::USER_TARGET_NOT_FOUND => [ + 'name' => Exception::USER_TARGET_NOT_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' => 409, + ], /** Teams */ Exception::TEAM_NOT_FOUND => [ @@ -616,11 +647,6 @@ return [ 'description' => 'Project with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.', 'code' => 409, ], - Exception::PROJECT_UNKNOWN => [ - 'name' => Exception::PROJECT_UNKNOWN, - 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'code' => 400, - ], Exception::PROJECT_PROVIDER_DISABLED => [ 'name' => Exception::PROJECT_PROVIDER_DISABLED, 'description' => 'The chosen OAuth provider is disabled. You can enable the OAuth provider using the Appwrite console.', @@ -680,6 +706,7 @@ return [ 'name' => Exception::RULE_VERIFICATION_FAILED, 'description' => 'Domain verification failed. Please check if your DNS records are correct and try again.', 'code' => 401, + 'publish' => true ], Exception::PROJECT_SMTP_CONFIG_INVALID => [ 'name' => Exception::PROJECT_SMTP_CONFIG_INVALID, @@ -767,10 +794,132 @@ return [ ], /** Health */ - Exception::QUEUE_SIZE_EXCEEDED => [ - 'name' => Exception::QUEUE_SIZE_EXCEEDED, + Exception::HEALTH_QUEUE_SIZE_EXCEEDED => [ + 'name' => Exception::HEALTH_QUEUE_SIZE_EXCEEDED, 'description' => 'Queue size threshold hit.', 'code' => 503, 'publish' => false ], + + Exception::HEALTH_CERTIFICATE_EXPIRED => [ + 'name' => Exception::HEALTH_CERTIFICATE_EXPIRED, + 'description' => 'The SSL certificate for the specified domain has expired and is no longer valid.', + 'code' => 404, + ], + + Exception::HEALTH_INVALID_HOST => [ + 'name' => Exception::HEALTH_INVALID_HOST, + 'description' => 'Failed to establish a connection to the specified domain. Please verify the domain name and ensure that the server is running and accessible.', + 'code' => 404, + ], + + /** Providers */ + Exception::PROVIDER_NOT_FOUND => [ + 'name' => Exception::PROVIDER_NOT_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 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 => [ + 'name' => Exception::TOPIC_NOT_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, + ], + + /** Subscribers */ + 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, + ], + + /** Messages */ + Exception::MESSAGE_NOT_FOUND => [ + 'name' => Exception::MESSAGE_NOT_FOUND, + '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 has no recipients (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.', + 'code' => 400, + ], + Exception::MESSAGE_ALREADY_PROCESSING => [ + 'name' => Exception::MESSAGE_ALREADY_PROCESSING, + 'description' => 'Message with the requested ID is already being processed.', + 'code' => 400, + ], + Exception::MESSAGE_ALREADY_FAILED => [ + 'name' => Exception::MESSAGE_ALREADY_FAILED, + 'description' => 'Message with the requested ID has already failed.', + '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, + ], + 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, + ], + Exception::MESSAGE_MISSING_SCHEDULE => [ + 'name' => Exception::MESSAGE_MISSING_SCHEDULE, + 'description' => 'Message can not have status ' . MessageStatus::SCHEDULED . ' without a schedule.', + 'code' => 400, + ], + Exception::SCHEDULE_NOT_FOUND => [ + 'name' => Exception::SCHEDULE_NOT_FOUND, + 'description' => 'Schedule with the requested ID could not be found.', + 'code' => 404, + ], + + /** Targets */ + Exception::TARGET_PROVIDER_INVALID_TYPE => [ + 'name' => Exception::TARGET_PROVIDER_INVALID_TYPE, + 'description' => 'Target has an invalid provider type.', + 'code' => 400, + ], ]; diff --git a/app/config/events.php b/app/config/events.php index c0b6cc3b41..5378502faf 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -44,6 +44,28 @@ 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.', + ], + ], + 'tokens' => [ + '$model' => Response::MODEL_TOKEN, + '$resource' => true, + '$description' => 'This event triggers on any user\'s token event.', + 'create' => [ + '$description' => 'This event triggers when a user\'s token is created.', + ], + ], 'create' => [ '$description' => 'This event triggers when a user is created.' ], @@ -237,6 +259,56 @@ return [ '$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.', + ], + 'update' => [ + '$description' => 'This event triggers when a message is updated.', + ], + ], + 'topics' => [ + '$model' => Response::MODEL_TOPIC, + '$resource' => true, + '$description' => 'This event triggers on any topic event.', + 'create' => [ + '$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 topic 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.' + ], + ], + ], + '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, 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 new file mode 100644 index 0000000000..4d6972389e --- /dev/null +++ b/app/config/locale/templates/email-base-styled.tpl @@ -0,0 +1,207 @@ + + + + + + + + + + + +
+ + + + +
+ +
+ + + + + +
+

{{subject}}

+
+ + + + + +
+{{body}} +
+ + + + + +
+ + + + + + + +
+ + + + + +
+ + + + + + +
Terms +
|
+
Privacy
+

+ © {{year}} Appwrite | 251 Little Falls Drive, Wilmington 19808, + Delaware, United States +

+
+ + \ No newline at end of file diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index f41a9530e1..13056fd5ae 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -1,5 +1,74 @@ + + + + + + @@ -8,13 +77,14 @@ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Poppins:wght@500;600&display=swap" rel="stylesheet">