diff --git a/.claude/skills/pr-workflow/SKILL.md b/.claude/skills/pr-workflow/SKILL.md new file mode 100644 index 0000000000..f2e04477e5 --- /dev/null +++ b/.claude/skills/pr-workflow/SKILL.md @@ -0,0 +1,31 @@ +# PR Workflow for Appwrite + +## Branch Targeting + +**Important:** Appwrite does NOT use `main` as the primary development branch. + +PRs should target the **current version branch** (e.g., `1.8.x`, `1.9.x`), not `main`. + +### How to determine the correct target branch + +1. Check which version branch you're currently on: `git branch --show-current` +2. Look for branches matching the pattern `X.Y.x` (e.g., `1.8.x`, `1.9.x`) +3. The current active development branch is typically the highest version number with the `.x` suffix + +### When creating PRs + +Always use the version branch as the base: + +```bash +# Correct - targets the version branch +gh pr create --base 1.8.x --title "Your PR title" --body "..." + +# Wrong - do not target main +gh pr create --base main ... +``` + +### Branch naming convention + +- `X.Y.x` branches (e.g., `1.8.x`) - Active development branches for each minor version +- `main` - Not used for regular PRs; reserved for release management +- Feature branches should be created from and merged back into the current version branch diff --git a/.env b/.env index 64fc7ef10f..726043414a 100644 --- a/.env +++ b/.env @@ -2,6 +2,7 @@ _APP_ENV=development _APP_EDITION=self-hosted _APP_LOCALE=en _APP_WORKER_PER_CORE=6 +_APP_COMPRESSION_ENABLED=enabled _APP_COMPRESSION_MIN_SIZE_BYTES=1024 _APP_CONSOLE_WHITELIST_ROOT=disabled _APP_CONSOLE_WHITELIST_EMAILS= @@ -9,6 +10,7 @@ _APP_CONSOLE_SESSION_ALERTS=enabled _APP_CONSOLE_WHITELIST_IPS= _APP_CONSOLE_COUNTRIES_DENYLIST=AQ _APP_CONSOLE_HOSTNAMES=localhost,appwrite.io,*.appwrite.io +_APP_MIGRATION_HOST=appwrite _APP_SYSTEM_EMAIL_NAME=Appwrite _APP_SYSTEM_EMAIL_ADDRESS=noreply@appwrite.io _APP_SYSTEM_TEAM_EMAIL=team@appwrite.io @@ -24,8 +26,9 @@ _APP_OPENSSL_KEY_V1=your-secret-key _APP_DNS=172.16.238.100 # CoreDNS _APP_DOMAIN=appwrite.test _APP_CONSOLE_DOMAIN=localhost +_APP_CONSOLE_TRUSTED_PROJECTS=trusted-project,another-trusted-project _APP_DOMAIN_FUNCTIONS=functions.localhost -_APP_DOMAIN_SITES=sites.localhost +_APP_DOMAIN_SITES=sites.localhost,rebranded.localhost _APP_DOMAIN_TARGET_CNAME=cname.localhost _APP_DOMAIN_TARGET_A=203.0.0.1 _APP_DOMAIN_TARGET_AAAA=::1 @@ -35,6 +38,7 @@ _APP_REDIS_HOST=redis _APP_REDIS_PORT=6379 _APP_REDIS_PASS= _APP_REDIS_USER= +_APP_DB_ADAPTER=mariadb _APP_DB_HOST=mariadb _APP_DB_PORT=3306 _APP_DB_SCHEMA=appwrite @@ -69,8 +73,8 @@ _APP_STORAGE_ANTIVIRUS_PORT=3310 _APP_SMTP_HOST=maildev _APP_SMTP_PORT=1025 _APP_SMTP_SECURE= -_APP_SMTP_USERNAME= -_APP_SMTP_PASSWORD= +_APP_SMTP_USERNAME=user +_APP_SMTP_PASSWORD=password _APP_SMS_PROVIDER=sms://username:password@mock _APP_SMS_FROM=+123456789 _APP_SMS_PROJECTS_DENY_LIST= @@ -101,9 +105,12 @@ _APP_USAGE_AGGREGATION_INTERVAL=30 _APP_STATS_RESOURCES_INTERVAL=30 _APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000 _APP_MAINTENANCE_RETENTION_SCHEDULES=86400 +_APP_INTERVAL_DOMAIN_VERIFICATION=120 +_APP_INTERVAL_CLEANUP_STALE_EXECUTIONS=300 _APP_USAGE_STATS=enabled _APP_LOGGING_CONFIG= _APP_LOGGING_CONFIG_REALTIME= +_APP_GRAPHQL_INTROSPECTION=enabled _APP_GRAPHQL_MAX_BATCH_SIZE=10 _APP_GRAPHQL_MAX_COMPLEXITY=250 _APP_GRAPHQL_MAX_DEPTH=4 @@ -125,4 +132,5 @@ _APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10 _APP_PROJECT_REGIONS=default _APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000 _APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main -_APP_TRUSTED_HEADERS=x-forwarded-for \ No newline at end of file +_APP_TRUSTED_HEADERS=x-forwarded-for +_APP_POOL_ADAPTER=stack \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cebdc02163..fc678a72da 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -80,6 +80,9 @@ jobs: name: Unit Test runs-on: ubuntu-latest needs: setup + permissions: + contents: read + pull-requests: write steps: - name: checkout @@ -108,15 +111,25 @@ jobs: run: docker compose exec -T appwrite vars - name: Run Unit Tests - run: | - docker compose exec \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/unit + command: >- + docker compose exec + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" appwrite test /usr/src/code/tests/unit e2e_general_test: name: E2E General Test runs-on: ubuntu-latest needs: setup + permissions: + contents: read + pull-requests: write steps: - name: checkout uses: actions/checkout@v4 @@ -143,9 +156,16 @@ jobs: done - name: Run General Tests - run: | - docker compose exec -T \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/General + command: >- + docker compose exec -T + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" appwrite test /usr/src/code/tests/e2e/General --debug - name: Failure Logs @@ -160,9 +180,17 @@ jobs: name: E2E Service Test runs-on: ubuntu-latest needs: setup + permissions: + contents: read + pull-requests: write strategy: fail-fast: false matrix: + db_adapter: [ + MARIADB, + POSTGRESQL + ] + service: [ Account, Avatars, @@ -214,16 +242,44 @@ jobs: done - name: Run ${{ matrix.service }} tests with Project table mode - run: | - echo "Using project tables" - export _APP_DATABASE_SHARED_TABLES= - export _APP_DATABASE_SHARED_TABLES_V1= + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/Services/${{ matrix.service }} + command: | + echo "Using project tables" - docker compose exec -T \ - -e _APP_DATABASE_SHARED_TABLES \ - -e _APP_DATABASE_SHARED_TABLES_V1 \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ - appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots + export _APP_DATABASE_SHARED_TABLES= + export _APP_DATABASE_SHARED_TABLES_V1= + + # Set DB Adapter Specific ENV Vars using if-elif + if [ "${{ matrix.db_adapter }}" = "MARIADB" ]; then + export _APP_DB_ADAPTER=mariadb + export _APP_DB_HOST=mariadb + export _APP_DB_PORT=3306 + export _APP_DB_SCHEMA=appwrite + elif [ "${{ matrix.db_adapter }}" = "POSTGRESQL" ]; then + export _APP_DB_ADAPTER=postgresql + export _APP_DB_HOST=postgresql + export _APP_DB_PORT=5432 + export _APP_DB_SCHEMA=appwrite + else + echo "Unknown DB adapter: ${{ matrix.db_adapter }}" + exit 1 + fi + + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_DB_ADAPTER \ + -e _APP_DB_HOST \ + -e _APP_DB_PORT \ + -e _APP_DB_SCHEMA \ + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group abuseEnabled,screenshots - name: Failure Logs if: failure() @@ -238,6 +294,9 @@ jobs: runs-on: ubuntu-latest needs: [ setup, check_database_changes ] if: needs.check_database_changes.outputs.database_changed == 'true' + permissions: + contents: read + pull-requests: write strategy: fail-fast: false matrix: @@ -297,22 +356,29 @@ jobs: done - name: Run ${{ matrix.service }} tests with ${{ matrix.tables-mode }} table mode - run: | - if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then - echo "Using shared tables V1" - export _APP_DATABASE_SHARED_TABLES=database_db_main - export _APP_DATABASE_SHARED_TABLES_V1=database_db_main - elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then - echo "Using shared tables V2" - export _APP_DATABASE_SHARED_TABLES=database_db_main - export _APP_DATABASE_SHARED_TABLES_V1= - fi - - docker compose exec -T \ - -e _APP_DATABASE_SHARED_TABLES \ - -e _APP_DATABASE_SHARED_TABLES_V1 \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ - appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/Services/${{ matrix.service }} + command: | + if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then + echo "Using shared tables V1" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1=database_db_main + elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then + echo "Using shared tables V2" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1= + fi + + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group abuseEnabled,screenshots - name: Failure Logs if: failure() @@ -322,10 +388,13 @@ jobs: echo "=== OpenRuntimes Executor Logs ===" docker compose logs openruntimes-executor - e2e_dev_keys: - name: E2E Service Test (Dev Keys) + e2e_abuse_enabled: + name: E2E Service Test (Abuse enabled) runs-on: ubuntu-latest needs: setup + permissions: + contents: read + pull-requests: write steps: - name: checkout uses: actions/checkout@v4 @@ -344,17 +413,24 @@ jobs: docker compose up -d sleep 30 - - name: Run Projects tests with dev keys in dedicated table mode - run: | - echo "Using project tables" - export _APP_DATABASE_SHARED_TABLES= - export _APP_DATABASE_SHARED_TABLES_V1= + - name: Run Projects tests in dedicated table mode + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/Services/Projects + command: | + echo "Using project tables" + export _APP_DATABASE_SHARED_TABLES= + export _APP_DATABASE_SHARED_TABLES_V1= - docker compose exec -T \ - -e _APP_DATABASE_SHARED_TABLES \ - -e _APP_DATABASE_SHARED_TABLES_V1 \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ - appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=abuseEnabled - name: Failure Logs if: failure() @@ -364,11 +440,14 @@ jobs: echo "=== OpenRuntimes Executor Logs ===" docker compose logs openruntimes-executor - e2e_dev_keys_shared_mode: - name: E2E Shared Mode Service Test (Dev Keys) + e2e_abuse_enabled_shared_mode: + name: E2E Shared Mode Service Test (Abuse enabled) runs-on: ubuntu-latest needs: [ setup, check_database_changes ] if: needs.check_database_changes.outputs.database_changed == 'true' + permissions: + contents: read + pull-requests: write strategy: fail-fast: false matrix: @@ -394,23 +473,30 @@ jobs: docker compose up -d sleep 30 - - name: Run Projects tests with dev keys in ${{ matrix.tables-mode }} table mode - run: | - if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then - echo "Using shared tables V1" - export _APP_DATABASE_SHARED_TABLES=database_db_main - export _APP_DATABASE_SHARED_TABLES_V1=database_db_main - elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then - echo "Using shared tables V2" - export _APP_DATABASE_SHARED_TABLES=database_db_main - export _APP_DATABASE_SHARED_TABLES_V1= - fi + - name: Run Projects tests in ${{ matrix.tables-mode }} table mode + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/Services/Projects + command: | + if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then + echo "Using shared tables V1" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1=database_db_main + elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then + echo "Using shared tables V2" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1= + fi - docker compose exec -T \ - -e _APP_DATABASE_SHARED_TABLES \ - -e _APP_DATABASE_SHARED_TABLES_V1 \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ - appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=abuseEnabled - name: Failure Logs if: failure() @@ -420,10 +506,13 @@ jobs: echo "=== OpenRuntimes Executor Logs ===" docker compose logs openruntimes-executor - e2e_screenshots_keys: + e2e_screenshots: name: E2E Service Test (Site Screenshots) runs-on: ubuntu-latest needs: setup + permissions: + contents: read + pull-requests: write steps: - name: checkout uses: actions/checkout@v4 @@ -443,17 +532,24 @@ jobs: sleep 30 - name: Run Site tests with browser connected in dedicated table mode - run: | - echo "Keeping original value of _APP_BROWSER_HOST" - echo "Using project tables" - export _APP_DATABASE_SHARED_TABLES= - export _APP_DATABASE_SHARED_TABLES_V1= + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/Services/Sites + command: | + echo "Keeping original value of _APP_BROWSER_HOST" + echo "Using project tables" + export _APP_DATABASE_SHARED_TABLES= + export _APP_DATABASE_SHARED_TABLES_V1= - docker compose exec -T \ - -e _APP_DATABASE_SHARED_TABLES \ - -e _APP_DATABASE_SHARED_TABLES_V1 \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ - appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots - name: Failure Logs if: failure() @@ -468,6 +564,9 @@ jobs: runs-on: ubuntu-latest needs: [ setup, check_database_changes ] if: needs.check_database_changes.outputs.database_changed == 'true' + permissions: + contents: read + pull-requests: write strategy: fail-fast: false matrix: @@ -494,23 +593,30 @@ jobs: sleep 30 - name: Run Site tests with browser connected in ${{ matrix.tables-mode }} table mode - run: | - echo "Keeping original value of _APP_BROWSER_HOST" - if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then - echo "Using shared tables V1" - export _APP_DATABASE_SHARED_TABLES=database_db_main - export _APP_DATABASE_SHARED_TABLES_V1=database_db_main - elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then - echo "Using shared tables V2" - export _APP_DATABASE_SHARED_TABLES=database_db_main - export _APP_DATABASE_SHARED_TABLES_V1= - fi + uses: itznotabug/php-retry@v3 + with: + max_attempts: 3 + timeout_minutes: 30 + job_id: ${{ job.check_run_id }} + github_token: ${{ secrets.GITHUB_TOKEN }} + test_dir: tests/e2e/Services/Sites + command: | + echo "Keeping original value of _APP_BROWSER_HOST" + if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then + echo "Using shared tables V1" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1=database_db_main + elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then + echo "Using shared tables V2" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1= + fi - docker compose exec -T \ - -e _APP_DATABASE_SHARED_TABLES \ - -e _APP_DATABASE_SHARED_TABLES_V1 \ - -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ - appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ + appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots - name: Failure Logs if: failure() @@ -518,4 +624,4 @@ jobs: echo "=== Appwrite Worker Builds Logs ===" docker compose logs appwrite-worker-builds echo "=== OpenRuntimes Executor Logs ===" - docker compose logs openruntimes-executor \ No newline at end of file + docker compose logs openruntimes-executor diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..993b0b5ad0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,77 @@ +# AGENTS.md + +Appwrite is an end-to-end backend server for web, mobile, native, and backend apps. This guide provides context and instructions for AI coding agents working on the Appwrite codebase. + +## Project Overview + +Appwrite is a self-hosted Backend-as-a-Service (BaaS) platform that provides developers with a set of APIs and tools to build secure, scalable applications. The project uses a hybrid monolithic-microservice architecture built with PHP, running on Swoole for high performance. + +**Key Technologies:** +- **Backend:** PHP 8.3+, Swoole +- **Libraries:** Utopia PHP +- **Database:** MariaDB, Redis +- **Cache:** Redis +- **Queue:** Redis +- **Containers:** Docker + +## Development Commands + +```bash +# Run Appwrite +docker compose up -d --force-recreate --build + +# Run specific test +docker compose exec appwrite test /usr/src/code/tests/e2e/Services/[ServiceName] --filter=[FunctionName] + +# Format code +composer format +``` + +## Code Style Guidelines + +- Follow [PSR-12](https://www.php-fig.org/psr/psr-12/) coding standard +- Use PSR-4 autoloading +- Strict type declarations where applicable +- Comprehensive PHPDoc comments + +### Naming Conventions + +#### `resourceType` Naming Rule + +When a collection has a combination of `resourceType`, `resourceId`, and/or `resourceInternalId`, the value of `resourceType` MUST always be **plural** - for example: `functions`, `sites`, `deployments`. + +Examples: +```php +'resourceType' => 'functions' +'resourceType' => 'sites' +'resourceType' => 'deployments' +``` + +## Security Considerations + +### Critical Security Practices + +- **Never hardcode credentials** - Use environment variables +- **Rate limiting** - Respect abuse prevention mechanisms + +## Dependencies + +Avoid introducing new dependencies other than utopia-php. + +## Adding new endpoints + +When adding new endpoints, make sure to use modules and follow its patterns. Find instruction in [Modules AGENTS.md](src/Appwrite/Platform/AGENTS.md) file. + +## Pull Request Guidelines +### Before Submitting + +- Run `composer format` +- Update documentation if adding features +- Add/update tests for your changes +- Check that Docker build succeeds +`docs/specs/authentication.drawio.svg` + +## Known Issues and Gotchas + +- **Hot Reload:** Code changes require container restart in some cases +- **Logging:** There is no central place for logs, so when debugging, ensure to check all possibly relevant containers diff --git a/CHANGES.md b/CHANGES.md index 74b46b7edc..e6dd04b556 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,101 @@ +# Version 1.8.1 + +## What's Changed + +### Notable changes + +* Add branch deployments support in [#10486](https://github.com/appwrite/appwrite/pull/10486) +* Add TanStack Start sites support in [#10681](https://github.com/appwrite/appwrite/pull/10681) +* Add Next.js standalone support in [#10747](https://github.com/appwrite/appwrite/pull/10747) +* Add Resend integration in [#10690](https://github.com/appwrite/appwrite/pull/10690) +* Add option to enable/disable image transformations per-bucket in [#10722](https://github.com/appwrite/appwrite/pull/10722) +* Add operators support in [#10735](https://github.com/appwrite/appwrite/pull/10735) and [#10800](https://github.com/appwrite/appwrite/pull/10800) +* Add function and sites stats in [#10786](https://github.com/appwrite/appwrite/pull/10786) +* Add disable count feature in [#10668](https://github.com/appwrite/appwrite/pull/10668) +* Add ElevenLabs site template in [#10782](https://github.com/appwrite/appwrite/pull/10782) +* Add suggested environment variables in [#10795](https://github.com/appwrite/appwrite/pull/10795) +* Update GeoDB database in [#10890](https://github.com/appwrite/appwrite/pull/10890) +* Update Flutter default build runtime in [#10807](https://github.com/appwrite/appwrite/pull/10807) +* Upgrade runtimes in [#10804](https://github.com/appwrite/appwrite/pull/10804) + +### Fixes + +* Fix duplicate document error while creating file in [#10891](https://github.com/appwrite/appwrite/pull/10891) +* Fix "Update external deployment (authorize)" throwing 500 error due to invalid query in [#10888](https://github.com/appwrite/appwrite/pull/10888) +* Fix error setting user password in [#10889](https://github.com/appwrite/appwrite/pull/10889) +* Fix error generating email MFA challenges in [#10884](https://github.com/appwrite/appwrite/pull/10884) +* Fix file token expiry in [#10877](https://github.com/appwrite/appwrite/pull/10877) +* Fix TanStack Nitro default in [#10860](https://github.com/appwrite/appwrite/pull/10860) +* Fix TanStack builds in [#10767](https://github.com/appwrite/appwrite/pull/10767) +* Fix nullable validation in [#10819](https://github.com/appwrite/appwrite/pull/10819) and [#10778](https://github.com/appwrite/appwrite/pull/10778) +* Fix WebP library in [#10738](https://github.com/appwrite/appwrite/pull/10738) +* Fix batch writes in [#10812](https://github.com/appwrite/appwrite/pull/10812) +* Fix error handler error in [#10719](https://github.com/appwrite/appwrite/pull/10719) +* Fix Next 16 compatibility in [#10713](https://github.com/appwrite/appwrite/pull/10713) +* Fix stats usage memory leak in [#10683](https://github.com/appwrite/appwrite/pull/10683) +* Fix author URL in template deployments in [#10535](https://github.com/appwrite/appwrite/pull/10535) +* Fix VCS lock deletion in [#10691](https://github.com/appwrite/appwrite/pull/10691) + +### Miscellaneous + +* Add CSV export functionality in [#10546](https://github.com/appwrite/appwrite/pull/10546), [#10750](https://github.com/appwrite/appwrite/pull/10750), [#10813](https://github.com/appwrite/appwrite/pull/10813), and [#10847](https://github.com/appwrite/appwrite/pull/10847) +* Add JWT disposition in [#10867](https://github.com/appwrite/appwrite/pull/10867) +* Add screenshots endpoint in [#10675](https://github.com/appwrite/appwrite/pull/10675) +* Add screenshot endpoint stats in [#10706](https://github.com/appwrite/appwrite/pull/10706) +* Add users attributes in [#10688](https://github.com/appwrite/appwrite/pull/10688) +* Add max build duration environment variable in [#10674](https://github.com/appwrite/appwrite/pull/10674) +* Add custom realtime logger in [#10871](https://github.com/appwrite/appwrite/pull/10871) +* Add logs in [#10869](https://github.com/appwrite/appwrite/pull/10869) +* Improve MFA docs endpoint order in [#10793](https://github.com/appwrite/appwrite/pull/10793) +* Auth refactor in [#10758](https://github.com/appwrite/appwrite/pull/10758), [#10837](https://github.com/appwrite/appwrite/pull/10837), [#10682](https://github.com/appwrite/appwrite/pull/10682), and [#10667](https://github.com/appwrite/appwrite/pull/10667) +* Bump assistant to 0.8.4 in [#10887](https://github.com/appwrite/appwrite/pull/10887) +* Bump database to 3.1.5 in [#10766](https://github.com/appwrite/appwrite/pull/10766) +* Bump Utopia DNS in [#10761](https://github.com/appwrite/appwrite/pull/10761) +* Update domains to 0.8.3 in [#10658](https://github.com/appwrite/appwrite/pull/10658) +* Update domains to 0.9.1 in [#10678](https://github.com/appwrite/appwrite/pull/10678) +* Update Apple Swift to 13.3.0 in [#10679](https://github.com/appwrite/appwrite/pull/10679) +* Update Apple Swift in [#10663](https://github.com/appwrite/appwrite/pull/10663) +* Update CLI to 10.2.2 in [#10672](https://github.com/appwrite/appwrite/pull/10672) +* Update to CLI 12.0.0 in [#10853](https://github.com/appwrite/appwrite/pull/10853) +* Update docs examples to use Permission class in [#10707](https://github.com/appwrite/appwrite/pull/10707) +* Update SDK examples docs in [#10855](https://github.com/appwrite/appwrite/pull/10855) +* Release Python SDK in [#10762](https://github.com/appwrite/appwrite/pull/10762) +* Release Flutter 20.3.2 in [#10838](https://github.com/appwrite/appwrite/pull/10838) +* Release Flutter/Dart add screenshot examples in [#10811](https://github.com/appwrite/appwrite/pull/10811) +* Release PHP CLI in [#10791](https://github.com/appwrite/appwrite/pull/10791) +* Release SDKs in [#10817](https://github.com/appwrite/appwrite/pull/10817) +* Update SDKs in [#10694](https://github.com/appwrite/appwrite/pull/10694), [#10729](https://github.com/appwrite/appwrite/pull/10729), and [#10744](https://github.com/appwrite/appwrite/pull/10744) +* Update SDK generator in [#10743](https://github.com/appwrite/appwrite/pull/10743) +* Update database in [#10664](https://github.com/appwrite/appwrite/pull/10664) +* Update README file in [#10763](https://github.com/appwrite/appwrite/pull/10763) +* SDK release documentation in [#10745](https://github.com/appwrite/appwrite/pull/10745) +* SDK release runtime config in [#10765](https://github.com/appwrite/appwrite/pull/10765) +* Sync specs in [#10789](https://github.com/appwrite/appwrite/pull/10789) +* Sync 1.8.0 in [#10677](https://github.com/appwrite/appwrite/pull/10677) +* Add workflow for issue triage in [#10718](https://github.com/appwrite/appwrite/pull/10718) +* Add issue auto-labeler in [#10700](https://github.com/appwrite/appwrite/pull/10700) +* Add AI moderator repo in [#10717](https://github.com/appwrite/appwrite/pull/10717) +* Browser bump in [#10850](https://github.com/appwrite/appwrite/pull/10850) +* Template type enum override in [#10848](https://github.com/appwrite/appwrite/pull/10848) +* VCS reference type in [#10852](https://github.com/appwrite/appwrite/pull/10852) +* Index scope description in [#10851](https://github.com/appwrite/appwrite/pull/10851) +* Config for environment in [#10833](https://github.com/appwrite/appwrite/pull/10833) +* Format instance in [#10830](https://github.com/appwrite/appwrite/pull/10830) +* Replace sleep in webhooks service in [#10656](https://github.com/appwrite/appwrite/pull/10656) +* Update email composer in [#10720](https://github.com/appwrite/appwrite/pull/10720) +* Update facts on GitHub sites and functions in [#10593](https://github.com/appwrite/appwrite/pull/10593) and [#10771](https://github.com/appwrite/appwrite/pull/10771) +* Fix wrong user type in [#10875](https://github.com/appwrite/appwrite/pull/10875) +* Fix limit and offset computation in [#10880](https://github.com/appwrite/appwrite/pull/10880) +* Fix enum examples in [#10828](https://github.com/appwrite/appwrite/pull/10828) +* Fix response models multi-methods in [#10815](https://github.com/appwrite/appwrite/pull/10815) +* Fix undefined variable in [#10654](https://github.com/appwrite/appwrite/pull/10654) +* Fix undefined sequence in [#10652](https://github.com/appwrite/appwrite/pull/10652) +* Fix description in [#10702](https://github.com/appwrite/appwrite/pull/10702) +* Fix warning in builds worker in [#10705](https://github.com/appwrite/appwrite/pull/10705) +* Fix sites create deployment docs in [#10566](https://github.com/appwrite/appwrite/pull/10566) +* Fix test dependencies projects in [#10655](https://github.com/appwrite/appwrite/pull/10655) +* Fix list sites test in [#10726](https://github.com/appwrite/appwrite/pull/10726) + # Version 1.8.0 ## What's Changed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 96b0614165..c6837673d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -222,73 +222,51 @@ Appwrite's current structure is a combination of both [Monolithic](https://en.wi ```bash . ├── app # Main application -│ ├── assets -│ │ ├── dbip -│ │ ├── fonts -│ │ └── security │ ├── config # Config files -│ │ ├── avatars -│ │ ├── collections -│ │ ├── locale -│ │ ├── specs -│ │ ├── storage -│ │ └── templates │ ├── controllers # API & dashboard controllers │ │ ├── api │ │ ├── shared │ │ └── web -│ ├── init # DB schemas -│ │ └── database -│ └── views # HTML server-side templates -│ ├── general -│ └── install +│ ├── db # DB schemas +│ ├── sdks # SDKs generated copies (used for generating code examples) +│ ├── tasks # Server CLI commands +│ ├── views # HTML server-side templates +│ └── workers # Background workers ├── bin # Server executables (tasks & workers) -├── dev # Debugger config +├── docker # Docker related resources and configs ├── docs # Docs and tutorials │ ├── examples -│ ├── lists │ ├── references -│ ├── sdks │ ├── services │ ├── specs │ └── tutorials ├── public # Public files +│ ├── dist │ ├── fonts │ ├── images -│ ├── sdk-console -│ ├── sdk-project -│ └── sdk-web -├── src # Supporting libraries (each lib has one role, common libs are released as -│ ├── Appwrite -│ │ ├── Auth -│ │ ├── Certificates -│ │ ├── Deletes -│ │ ├── Detector -│ │ ├── Docker -│ │ ├── Event -│ │ ├── Extend -│ │ ├── Functions/Validator -│ │ ├── GraphQL -│ │ ├── Hooks -│ │ ├── Messaging -│ │ ├── Migration -│ │ ├── Network -│ │ ├── OpenSSL -│ │ ├── Platform -│ │ ├── Promises -│ │ ├── PubSub -│ │ ├── SDK -│ │ ├── Task/Validator -│ │ ├── Template -│ │ ├── Transformation -│ │ ├── URL -│ │ ├── Utopia -│ │ └── Vcs -│ └── Executor +│ ├── scripts +│ └── styles +├── src # Supporting libraries (each lib has one role, common libs are released as individual projects) +│ └── Appwrite +│ ├── Auth +│ ├── Detector +│ ├── Docker +| ├── DSN +│ ├── Event +│ ├── Extend +│ ├── GraphQL +│ ├── Messaging +│ ├── Migration +│ ├── Network +│ ├── OpenSSL +│ ├── Promises +│ ├── Specification +│ ├── Task +│ ├── Template +│ ├── URL +│ └── Utopia └── tests # End to end & unit tests - ├── benchmarks ├── e2e - ├── extensions ├── resources └── unit ``` diff --git a/Dockerfile b/Dockerfile index e146008222..9afe164809 100755 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ --no-plugins --no-scripts --prefer-dist \ `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi` -FROM appwrite/base:0.10.6 AS base +FROM appwrite/base:1.0.0 AS base LABEL maintainer="team@appwrite.io" @@ -57,6 +57,7 @@ RUN mkdir -p /storage/uploads && \ # Executables RUN chmod +x /usr/local/bin/doctor && \ chmod +x /usr/local/bin/install && \ + chmod +x /usr/local/bin/interval && \ chmod +x /usr/local/bin/maintenance && \ chmod +x /usr/local/bin/migrate && \ chmod +x /usr/local/bin/realtime && \ @@ -76,9 +77,11 @@ RUN chmod +x /usr/local/bin/doctor && \ 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-screenshots && \ 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-executions && \ chmod +x /usr/local/bin/worker-functions && \ chmod +x /usr/local/bin/worker-mails && \ chmod +x /usr/local/bin/worker-messaging && \ diff --git a/README-CN.md b/README-CN.md index c087b16201..afd7eca289 100644 --- a/README-CN.md +++ b/README-CN.md @@ -72,7 +72,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.8.0 + appwrite/appwrite:1.8.1 ``` ### Windows @@ -84,7 +84,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.8.0 + appwrite/appwrite:1.8.1 ``` #### PowerShell @@ -94,7 +94,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.8.0 + appwrite/appwrite:1.8.1 ``` 运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。 diff --git a/README.md b/README.md index 0743234954..4a71579207 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.8.0 + appwrite/appwrite:1.8.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.8.0 + appwrite/appwrite:1.8.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.8.0 + appwrite/appwrite:1.8.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. diff --git a/app/cli.php b/app/cli.php index 7b65ab8fa5..14ebea6e1c 100644 --- a/app/cli.php +++ b/app/cli.php @@ -16,13 +16,13 @@ use Swoole\Timer; use Utopia\Cache\Adapter\Pool as CachePool; use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; -use Utopia\CLI\CLI; -use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Console; use Utopia\Database\Adapter\Pool as DatabasePool; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; +use Utopia\DI\Dependency; use Utopia\DSN\DSN; use Utopia\Logger\Log; use Utopia\Platform\Service; @@ -30,6 +30,9 @@ use Utopia\Pools\Group; use Utopia\Queue\Broker\Pool as BrokerPool; use Utopia\Queue\Publisher; use Utopia\Registry\Registry; +use Utopia\Span\Exporter; +use Utopia\Span\Span; +use Utopia\Span\Storage; use Utopia\System\System; use Utopia\Telemetry\Adapter\None as NoTelemetry; @@ -41,9 +44,33 @@ Config::setParam('runtimes', (new Runtimes('v5'))->getAll(supported: false)); // require controllers after overwriting runtimes require_once __DIR__ . '/controllers/general.php'; -CLI::setResource('register', fn () => $register); +global $register; -CLI::setResource('cache', function ($pools) { +$platform = new Appwrite(); +$args = $platform->getEnv('argv'); + +\array_shift($args); +if (!isset($args[0])) { + Console::error('Missing task name'); + Console::exit(1); +} + +$taskName = $args[0]; +$platform->init(Service::TYPE_TASK); +$cli = $platform->getCli(); + +$setResource = function (string $name, callable $callback, array $injections = []) use ($cli) { + $dependency = new Dependency(); + $dependency->setName($name)->setCallback($callback); + foreach ($injections as $injection) { + $dependency->inject($injection); + } + $cli->setResource($dependency); +}; + +$setResource('register', fn () => $register, []); + +$setResource('cache', function ($pools) { $list = Config::getParam('pools-cache', []); $adapters = []; @@ -54,17 +81,17 @@ CLI::setResource('cache', function ($pools) { return new Cache(new Sharding($adapters)); }, ['pools']); -CLI::setResource('pools', function (Registry $register) { +$setResource('pools', function (Registry $register) { return $register->get('pools'); }, ['register']); -CLI::setResource('authorization', function () { +$setResource('authorization', function () { $authorization = new Authorization(); $authorization->disable(); return $authorization; }, []); -CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { +$setResource('dbForPlatform', function ($pools, $cache, $authorization) { $sleep = 3; $maxAttempts = 5; $attempts = 0; @@ -78,6 +105,7 @@ CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { $dbForPlatform = new Database($adapter, $cache); $dbForPlatform + ->setDatabase(APP_DATABASE) ->setAuthorization($authorization) ->setNamespace('_console') ->setMetadata('host', \gethostname()) @@ -106,16 +134,17 @@ CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) { return $dbForPlatform; }, ['pools', 'cache', 'authorization']); -CLI::setResource('console', function () { +$setResource('console', function () { return new Document(Config::getParam('console')); }, []); -CLI::setResource( +$setResource( 'isResourceBlocked', - fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false + fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false, + [] ); -CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, $authorization) { +$setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, $authorization) { $databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) { @@ -168,6 +197,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform } $database + ->setDatabase(APP_DATABASE) ->setAuthorization($authorization) ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()); @@ -176,7 +206,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform }; }, ['pools', 'dbForPlatform', 'cache', 'authorization']); -CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { +$setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) { $database = null; return function (?Document $project = null) use ($pools, $cache, $database, $authorization) { @@ -189,6 +219,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio $database = new Database($adapter, $cache); $database + ->setDatabase(APP_DATABASE) ->setAuthorization($authorization) ->setSharedTables(true) ->setNamespace('logsV1') @@ -203,40 +234,40 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizatio return $database; }; }, ['pools', 'cache', 'authorization']); -CLI::setResource('publisher', function (Group $pools) { +$setResource('publisher', function (Group $pools) { return new BrokerPool(publisher: $pools->get('publisher')); }, ['pools']); -CLI::setResource('publisherDatabases', function (BrokerPool $publisher) { +$setResource('publisherDatabases', function (BrokerPool $publisher) { return $publisher; }, ['publisher']); -CLI::setResource('publisherFunctions', function (BrokerPool $publisher) { +$setResource('publisherFunctions', function (BrokerPool $publisher) { return $publisher; }, ['publisher']); -CLI::setResource('publisherMigrations', function (BrokerPool $publisher) { +$setResource('publisherMigrations', function (BrokerPool $publisher) { return $publisher; }, ['publisher']); -CLI::setResource('publisherStatsUsage', function (BrokerPool $publisher) { +$setResource('publisherStatsUsage', function (BrokerPool $publisher) { return $publisher; }, ['publisher']); -CLI::setResource('publisherMessaging', function (BrokerPool $publisher) { +$setResource('publisherMessaging', function (BrokerPool $publisher) { return $publisher; }, ['publisher']); -CLI::setResource('queueForStatsUsage', function (Publisher $publisher) { +$setResource('queueForStatsUsage', function (Publisher $publisher) { return new StatsUsage($publisher); }, ['publisher']); -CLI::setResource('queueForStatsResources', function (Publisher $publisher) { +$setResource('queueForStatsResources', function (Publisher $publisher) { return new StatsResources($publisher); }, ['publisher']); -CLI::setResource('queueForFunctions', function (Publisher $publisher) { +$setResource('queueForFunctions', function (Publisher $publisher) { return new Func($publisher); }, ['publisher']); -CLI::setResource('queueForDeletes', function (Publisher $publisher) { +$setResource('queueForDeletes', function (Publisher $publisher) { return new Delete($publisher); }, ['publisher']); -CLI::setResource('queueForCertificates', function (Publisher $publisher) { +$setResource('queueForCertificates', function (Publisher $publisher) { return new Certificate($publisher); }, ['publisher']); -CLI::setResource('logError', function (Registry $register) { +$setResource('logError', function (Registry $register) { return function (Throwable $error, string $namespace, string $action) use ($register) { Console::error('[Error] Timestamp: ' . date('c', time())); Console::error('[Error] Type: ' . get_class($error)); @@ -265,6 +296,14 @@ CLI::setResource('logError', function (Registry $register) { $log->addExtra('trace', $error->getTraceAsString()); $log->addExtra('detailedTrace', $error->getTrace()); + if ($error->getPrevious() !== null) { + if ($error->getPrevious()->getMessage() != $error->getMessage()) { + $log->addExtra('previousMessage', $error->getPrevious()->getMessage()); + } + $log->addExtra('previousFile', $error->getPrevious()->getFile()); + $log->addExtra('previousLine', $error->getPrevious()->getLine()); + } + $log->setAction($action); $isProduction = System::getEnv('_APP_ENV', 'development') === 'production'; @@ -280,22 +319,9 @@ CLI::setResource('logError', function (Registry $register) { }; }, ['register']); -CLI::setResource('executor', fn () => new Executor()); +$setResource('executor', fn () => new Executor(), []); -CLI::setResource('telemetry', fn () => new NoTelemetry()); - -$platform = new Appwrite(); -$args = $platform->getEnv('argv'); - -if (!isset($args[0])) { - Console::error('Missing task name'); - Console::exit(1); -} - -\array_shift($args); -$taskName = $args[0]; -$platform->init(Service::TYPE_TASK); -$cli = $platform->getCli(); +$setResource('telemetry', fn () => new NoTelemetry(), []); $cli ->error() @@ -314,4 +340,6 @@ $cli $cli->shutdown()->action(fn () => Timer::clearAll()); Runtime::enableCoroutine(SWOOLE_HOOK_ALL); +Span::setStorage(new Storage\Coroutine()); +Span::addExporter(new Exporter\Stdout()); run($cli->run(...)); diff --git a/app/config/collections.php b/app/config/collections.php index 533dee57a8..a74e079dce 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -26,8 +26,8 @@ unset($common['files']); $collections = [ 'buckets' => $buckets, 'databases' => $databases, - 'projects' => array_merge($projects, $common), - 'console' => array_merge($platform, $common), + 'projects' => array_merge_recursive($projects, $common), + 'console' => array_merge_recursive($platform, $common), 'logs' => $logs, ]; diff --git a/app/config/collections/common.php b/app/config/collections/common.php index a364a0a866..2328cd5b88 100644 --- a/app/config/collections/common.php +++ b/app/config/collections/common.php @@ -1288,6 +1288,17 @@ return [ 'array' => false, 'filters' => ['json'], ], + [ + '$id' => ID::custom('labels'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => true, + 'filters' => [], + ], ], 'indexes' => [ [ diff --git a/app/config/collections/platform.php b/app/config/collections/platform.php index d44d9b725c..84964ac96a 100644 --- a/app/config/collections/platform.php +++ b/app/config/collections/platform.php @@ -6,7 +6,7 @@ use Utopia\Database\Helpers\ID; $providers = Config::getParam('oAuthProviders', []); -return [ +$platformCollections = [ 'projects' => [ '$collection' => ID::custom(Database::METADATA), '$id' => ID::custom('projects'), @@ -330,7 +330,29 @@ return [ 'default' => null, 'array' => false, 'filters' => ['datetime'], - ] + ], + [ + '$id' => ID::custom('labels'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => 'status', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 100, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ @@ -622,24 +644,35 @@ return [ 'name' => 'keys', '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'), + '$id' => ID::custom('resourceType'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => Database::LENGTH_KEY, 'signed' => true, 'required' => false, - 'default' => 0, + '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('resourceInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, 'array' => false, 'filters' => [], ], @@ -712,14 +745,14 @@ return [ ], 'indexes' => [ [ - '$id' => ID::custom('_key_project'), + '$id' => ID::custom('_key_resource'), 'type' => Database::INDEX_KEY, - 'attributes' => ['projectInternalId'], - 'lengths' => [Database::LENGTH_KEY], - 'orders' => [Database::ORDER_ASC], + 'attributes' => ['resourceType', 'resourceInternalId'], + 'lengths' => [], + 'orders' => [], ], [ - '$id' => '_key_accessedAt', + '$id' => ID::custom('_key_accessedAt'), 'type' => Database::INDEX_KEY, 'attributes' => ['accessedAt'], 'lengths' => [], @@ -1362,21 +1395,21 @@ return [ '$id' => '_key_type', 'type' => Database::INDEX_KEY, 'attributes' => ['type'], - 'lengths' => [32], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => '_key_trigger', 'type' => Database::INDEX_KEY, 'attributes' => ['trigger'], - 'lengths' => [32], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ '$id' => '_key_deploymentResourceType', 'type' => Database::INDEX_KEY, 'attributes' => ['deploymentResourceType'], - 'lengths' => [32], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ @@ -1418,23 +1451,23 @@ return [ '$id' => ID::custom('_key_owner'), 'type' => Database::INDEX_KEY, 'attributes' => ['owner'], - 'lengths' => [16], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_region'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['region'], - 'lengths' => [16], - 'orders' => [Database::ORDER_ASC], - ], - [ - '$id' => ID::custom('_key_piid_riid_rt'), + '$id' => ID::custom('_key_piid_diid_drt'), 'type' => Database::INDEX_KEY, 'attributes' => ['projectInternalId', 'deploymentInternalId', 'deploymentResourceType'], 'lengths' => [], 'orders' => [], ], + [ + '$id' => '_key_region_status_createdAt', + 'type' => Database::INDEX_KEY, + 'attributes' => ['region', 'status', '$createdAt'], + 'lengths' => [], + 'orders' => [], + ], ], ], @@ -1903,3 +1936,31 @@ return [ 'indexes' => [] ], ]; + +// Organization API keys subquery +$platformCollections['teams']['attributes'][] = [ + '$id' => ID::custom('keys'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['subQueryOrganizationKeys'], +]; + +// Account API keys subquery +$platformCollections['users']['attributes'][] = [ + '$id' => ID::custom('keys'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['subQueryAccountKeys'], +]; + +return $platformCollections; diff --git a/app/config/collections/projects.php b/app/config/collections/projects.php index dae0337dc9..ecd3db1733 100644 --- a/app/config/collections/projects.php +++ b/app/config/collections/projects.php @@ -567,6 +567,17 @@ return [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('deploymentRetention'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('deploymentInternalId'), 'type' => Database::VAR_STRING, @@ -765,6 +776,17 @@ return [ 'default' => null, 'filters' => [], ], + [ + 'array' => false, + '$id' => ID::custom('startCommand'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 20000, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], [ 'array' => false, '$id' => ID::custom('specification'), @@ -776,6 +798,28 @@ return [ 'default' => APP_COMPUTE_SPECIFICATION_DEFAULT, 'filters' => [], ], + [ + 'array' => false, + '$id' => ID::custom('buildSpecification'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => false, + 'required' => false, + 'default' => APP_COMPUTE_SPECIFICATION_DEFAULT, + 'filters' => [], + ], + [ + 'array' => false, + '$id' => ID::custom('runtimeSpecification'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => false, + 'required' => false, + 'default' => APP_COMPUTE_SPECIFICATION_DEFAULT, + 'filters' => [], + ], [ '$id' => ID::custom('scopes'), 'type' => Database::VAR_STRING, @@ -1035,6 +1079,17 @@ return [ 'default' => null, 'filters' => [], ], + [ + 'array' => false, + '$id' => ID::custom('startCommand'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 20000, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], [ '$id' => ID::custom('fallbackFile'), 'type' => Database::VAR_STRING, @@ -1046,6 +1101,17 @@ return [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('deploymentRetention'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('deploymentInternalId'), 'type' => Database::VAR_STRING, @@ -1200,6 +1266,28 @@ return [ 'default' => APP_COMPUTE_SPECIFICATION_DEFAULT, 'filters' => [], ], + [ + 'array' => false, + '$id' => ID::custom('buildSpecification'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => false, + 'required' => false, + 'default' => APP_COMPUTE_SPECIFICATION_DEFAULT, + 'filters' => [], + ], + [ + 'array' => false, + '$id' => ID::custom('runtimeSpecification'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 128, + 'signed' => false, + 'required' => false, + 'default' => APP_COMPUTE_SPECIFICATION_DEFAULT, + 'filters' => [], + ], [ '$id' => ID::custom('buildRuntime'), 'type' => Database::VAR_STRING, @@ -1357,6 +1445,17 @@ return [ 'default' => null, 'filters' => [], ], + [ + 'array' => false, + '$id' => ID::custom('startCommand'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 20000, + 'signed' => true, + 'required' => false, + 'default' => null, + 'filters' => [], + ], [ 'array' => false, '$id' => ID::custom('buildOutput'), @@ -2098,6 +2197,13 @@ return [ 'lengths' => [], 'orders' => [], ], + [ + '$id' => ID::custom('_key_resourceType'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['resourceType'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ], ], ], diff --git a/app/config/errors.php b/app/config/errors.php index 6d747e4eb1..16fad57de1 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -357,6 +357,11 @@ return [ 'description' => 'API key and session used in the same request. Use either `setSession` or `setKey`. Learn about which authentication method to use in the SSR docs: https://appwrite.io/docs/products/auth/server-side-rendering', 'code' => 403, ], + Exception::USER_JWT_AND_COOKIE_SET => [ + 'name' => Exception::USER_JWT_AND_COOKIE_SET, + 'description' => 'JWT and cookie used in the same request. Use either `setJWT` or `setCookie`. Learn about which authentication method to use in the SSR docs: https://appwrite.io/docs/products/auth/server-side-rendering', + 'code' => 403, + ], Exception::API_KEY_EXPIRED => [ 'name' => Exception::API_KEY_EXPIRED, 'description' => 'The dynamic API key has expired. Please don\'t use dynamic API keys for more than duration of the execution.', @@ -1074,6 +1079,11 @@ return [ 'description' => 'The project key has expired. Please generate a new key using the Appwrite console.', 'code' => 401, ], + Exception::ACCOUNT_KEY_EXPIRED => [ + 'name' => Exception::ACCOUNT_KEY_EXPIRED, + 'description' => 'The account API 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.', @@ -1103,7 +1113,6 @@ return [ 'name' => Exception::RULE_VERIFICATION_FAILED, 'description' => 'Domain verification failed. Please check if your DNS records are correct and try again.', 'code' => 400, - 'publish' => true ], Exception::PROJECT_SMTP_CONFIG_INVALID => [ 'name' => Exception::PROJECT_SMTP_CONFIG_INVALID, @@ -1130,6 +1139,11 @@ return [ 'description' => 'Key with the requested ID could not be found.', 'code' => 404, ], + Exception::KEY_ALREADY_EXISTS => [ + 'name' => Exception::KEY_ALREADY_EXISTS, + 'description' => 'Key with the same ID already exists. Try again with a different ID.', + 'code' => 409, + ], Exception::PLATFORM_NOT_FOUND => [ 'name' => Exception::PLATFORM_NOT_FOUND, 'description' => 'Platform with the requested ID could not be found.', @@ -1329,4 +1343,19 @@ return [ 'description' => 'Target has an invalid provider type.', 'code' => 400, ], + Exception::USER_ID_MISSING => [ + 'name' => Exception::USER_ID_MISSING, + 'description' => 'When using account API key, make sure to pass x-appwrite-user header with your user ID.', + 'code' => 403, + ], + Exception::ORGANIZATION_ID_MISSING => [ + 'name' => Exception::ORGANIZATION_ID_MISSING, + 'description' => 'When using organization API key, make sure to pass x-appwrite-organization header with your organization ID.', + 'code' => 403, + ], + Exception::PROJECT_ID_MISSING => [ + 'name' => Exception::PROJECT_ID_MISSING, + 'description' => 'When using project API key, make sure to pass x-appwrite-project header with your project ID.', + 'code' => 403, + ], ]; diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index 338cc51252..312632a34a 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -50,17 +50,12 @@ font-style: normal; font-display: swap; } - - @font-face { - font-family: 'Poppins'; - src: url('https://assets.appwrite.io/fonts/poppins/poppins-v23-latin-regular.woff2') format('woff2'); - font-weight: 400; - font-style: normal; - font-display: swap; - }