diff --git a/.env b/.env index 227ea10676..65fb54cb04 100644 --- a/.env +++ b/.env @@ -56,7 +56,7 @@ _APP_SMTP_PORT=1025 _APP_SMTP_SECURE= _APP_SMTP_USERNAME= _APP_SMTP_PASSWORD= -_APP_SMS_PROVIDER=sms://mock +_APP_SMS_PROVIDER=sms://username:password@mock _APP_SMS_FROM=+123456789 _APP_STORAGE_LIMIT=30000000 _APP_STORAGE_PREVIEW_LIMIT=20000000 diff --git a/.gitattributes b/.gitattributes index beb791f5f3..6d7eedfcb5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -22,3 +22,7 @@ tests/*/*/* linguist-detectable=false tests/*/*/*/* linguist-detectable=false tests/*/*/*/*/* linguist-detectable=false tests/*/*/*/*/*/* linguist-detectable=false +public/scripts/* linguist-detectable=false +public/scripts/*/*/* linguist-detectable=false +public/scripts/*/*/*/* linguist-detectable=false +public/dist/scripts/* linguist-detectable=false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index faa18b5ab9..8522022bdb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -21,6 +21,11 @@ Happy contributing! (If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.) +### Have you added your change to the [Changelog](https://github.com/appwrite/appwrite/blob/master/CHANGES.md)? + +(The CHANGES.md file tracks all the changes that make it to the `main` branch. Add your change to this file in the following format) +- One line description of your PR [#pr_number](Link to your PR) + ### Have you read the [Contributing Guidelines on issues](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md)? (Write your answer here.) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2ed2b65ff7..1d1d10c8a1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,7 +4,7 @@ on: [pull_request] jobs: tests: name: Unit & E2E - runs-on: self-hosted + runs-on: ubuntu-latest steps: - name: Checkout repository @@ -23,12 +23,14 @@ jobs: # Upstream bug causes buildkit pulls to fail so prefetch base images # https://github.com/moby/moby/issues/41864 run: | - echo "_APP_FUNCTIONS_RUNTIMES=php-8.0" >> .env + export COMPOSE_INTERACTIVE_NO_CLI + export DOCKER_BUILDKIT=1 + export COMPOSE_DOCKER_CLI_BUILD=1 + export BUILDKIT_PROGRESS=plain docker pull composer:2.0 - docker pull php:8.0-cli-alpine - docker compose build --progress=plain + docker compose build appwrite docker compose up -d - sleep 10 + sleep 30 - name: Doctor run: docker compose exec -T appwrite doctor @@ -37,10 +39,3 @@ jobs: - name: Run Tests run: docker compose exec -T appwrite test --debug - - - name: Teardown - if: always() - run: | - docker ps -aq | xargs docker rm --force || true - docker volume prune --force || true - docker network prune --force || true \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 68ca4abd17..340aec16d4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,28 @@ +# Version 1.1.0 + +## Bugs +- Fix license detection for Flutter and Dart SDKs [#4435](https://github.com/appwrite/appwrite/pull/4435) + +# Version 1.0.3 +## Bugs +- Fix document audit deletion [#4429](https://github.com/appwrite/appwrite/pull/4429) +- Fix attribute and index deletion when deleting a collection [#4429](https://github.com/appwrite/appwrite/pull/4429) + +# Version 1.0.2 +## Bugs +- Fixed nullable values in functions variables [#3885](https://github.com/appwrite/appwrite/pull/3885) +- Fixed migration for audit by migrating the `time` attribute [#4038](https://github.com/appwrite/appwrite/pull/4038) +- Fixed default value for creating Boolean Attribute [#4040](https://github.com/appwrite/appwrite/pull/4040) +- Fixed phone authentication code to be hashed in the internal database [#3906](https://github.com/appwrite/appwrite/pull/3906) +- Fixed `/v1/teams/:teamId/memberships/:membershipId` response [#3883](https://github.com/appwrite/appwrite/pull/3883) +- Fixed removing variables when function is deleted [#3884](https://github.com/appwrite/appwrite/pull/3884) +- Fixed scheduled function not being triggered [#3908](https://github.com/appwrite/appwrite/pull/3908) +- Fixed Phone Provider configuration [#3862](https://github.com/appwrite/appwrite/pull/3883) +- Fixed Queries with `0` values [utopia-php/database#194](https://github.com/utopia-php/database/pull/194) + # Version 1.0.1 ## Bugs -- Fixed migration for abuse by migrating the `time` attribute [3839](https://github.com/appwrite/appwrite/pull/3839) +- Fixed migration for abuse by migrating the `time` attribute [#3839](https://github.com/appwrite/appwrite/pull/3839) # Version 1.0.0 ## BREAKING CHANGES diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e550c464b..5757b1c6ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,6 +93,7 @@ git clone git@github.com:[YOUR_FORK_HERE]/appwrite.git cd appwrite +docker compose build docker compose up -d ``` @@ -338,7 +339,7 @@ Things to remember when releasing SDKs 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 [PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) extension or if you are in PHP Storm you don't need any plugin. Below are the settings required for remote debugger connection. -First, you need to create an init file. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php** and there change the IP address to your development machine's IP. Without the proper IP address debugger wont connect. And you also need to set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file. +First, you need to create an init file. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php** and there change the IP address to your development machine's IP. Without the proper IP address debugger won't connect. And you also need to set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file. ### VS Code Launch Configuration @@ -378,7 +379,7 @@ To run end-2-end tests use: docker compose exec appwrite test /usr/src/code/tests/e2e ``` -To run end-2-end tests for a spcific service use: +To run end-2-end tests for a specific service use: ```bash docker compose exec appwrite test /usr/src/code/tests/e2e/Services/[ServiceName] diff --git a/README-CN.md b/README-CN.md index 82908f1425..eaada5a34b 100644 --- a/README-CN.md +++ b/README-CN.md @@ -8,13 +8,16 @@

- + + +[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=friendly&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github) -[![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite) -[![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite) +[![Build Status](https://img.shields.io/github/workflow/status/appwrite/appwrite/Tests?label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) -[![翻译](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md) -[![周边商店](https://img.shields.io/badge/swag%20store-f02e65?style=flat-square)](https://store.appwrite.io) + + + + [English](README.md) | 简体中文 @@ -59,7 +62,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.0.1 + appwrite/appwrite:1.0.3 ``` ### Windows @@ -71,7 +74,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.0.1 + appwrite/appwrite:1.0.3 ``` #### PowerShell @@ -81,7 +84,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.0.1 + appwrite/appwrite:1.0.3 ``` 运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。 @@ -128,7 +131,7 @@ docker run -it --rm , #### 服务器 * ✅   [NodeJS](https://github.com/appwrite/sdk-for-node) (由 Appwrite 团队维护) -* ✅   [PHP](https://github.com/appwrite/sdk-for-php) (由 Appwr实验 团队维护) +* ✅   [PHP](https://github.com/appwrite/sdk-for-php) (由 Appwrite 团队维护) * ✅   [Dart](https://github.com/appwrite/sdk-for-dart) - (由 Appwrite 团队维护) * ✅   [Deno](https://github.com/appwrite/sdk-for-deno) - **公测** (由 Appwrite 团队维护) * ✅   [Ruby](https://github.com/appwrite/sdk-for-ruby) (由 Appwrite 团队维护) diff --git a/README.md b/README.md index b9a895bc6e..0a56c48073 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,17 @@

- + + +[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=ready&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github) -[![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite) [![Build Status](https://img.shields.io/github/workflow/status/appwrite/appwrite/Tests?label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) -[![Translate](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md) -[![Swag Store](https://img.shields.io/badge/swag%20store-f02e65?style=flat-square)](https://store.appwrite.io) + + + + English | [简体中文](README-CN.md) @@ -28,6 +31,13 @@ Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend app Using Appwrite, you can easily integrate your app with user authentication & multiple sign-in methods, a database for storing and querying users and team data, storage and file management, image manipulation, Cloud Functions, and [more services](https://appwrite.io/docs). +

+
+ Appwrite - 100% open source alternative for Firebase | Product Hunt +
+
+

+ ![Appwrite](public/images/github.png) Find out more at: [https://appwrite.io](https://appwrite.io) @@ -65,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.0.1 + appwrite/appwrite:1.0.3 ``` ### Windows @@ -77,29 +87,27 @@ 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.0.1 + appwrite/appwrite:1.0.3 ``` #### PowerShell ```powershell -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.0.1 +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.0.3 ``` Once the Docker installation completes, 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 installation completes. - For advanced production and custom installation, check out our Docker [environment variables](https://appwrite.io/docs/environment-variables) docs. You can also use our public [docker-compose.yml](https://appwrite.io/install/compose) and [.env](https://appwrite.io/install/env) files to manually set up an environment. ### Upgrade from an Older Version If you are upgrading your Appwrite server from an older version, you should use the Appwrite migration tool once your setup is completed. For more information regarding this, check out the [Installation Docs](https://appwrite.io/docs/installation). - ## One-Click Setups In addition to running Appwrite locally, you can also launch Appwrite using a pre-configured setup. This allows you to get up and running with Appwrite quickly without installing Docker on your local machine. @@ -127,24 +135,24 @@ Choose from one of the providers below: Getting started with Appwrite is as easy as creating a new project, choosing your platform, and integrating its SDK into your code. You can easily get started with your platform of choice by reading one of our Getting Started tutorials. -* [Getting Started for Web](https://appwrite.io/docs/getting-started-for-web) -* [Getting Started for Flutter](https://appwrite.io/docs/getting-started-for-flutter) -* [Getting Started for Apple](https://appwrite.io/docs/getting-started-for-apple) -* [Getting Started for Android](https://appwrite.io/docs/getting-started-for-android) -* [Getting Started for Server](https://appwrite.io/docs/getting-started-for-server) -* [Getting Started for CLI](https://appwrite.io/docs/command-line) +- [Getting Started for Web](https://appwrite.io/docs/getting-started-for-web) +- [Getting Started for Flutter](https://appwrite.io/docs/getting-started-for-flutter) +- [Getting Started for Apple](https://appwrite.io/docs/getting-started-for-apple) +- [Getting Started for Android](https://appwrite.io/docs/getting-started-for-android) +- [Getting Started for Server](https://appwrite.io/docs/getting-started-for-server) +- [Getting Started for CLI](https://appwrite.io/docs/command-line) ### Services -* [**Account**](https://appwrite.io/docs/client/account) - Manage current user authentication and account. Track and manage the user sessions, devices, sign-in methods, and security logs. -* [**Users**](https://appwrite.io/docs/server/users) - Manage and list all project users when in admin mode. -* [**Teams**](https://appwrite.io/docs/client/teams) - Manage and group users in teams. Manage memberships, invites, and user roles within a team. -* [**Databases**](https://appwrite.io/docs/client/databases) - Manage databases, collections and documents. Read, create, update, and delete documents and filter lists of document collections using advanced filters. -* [**Storage**](https://appwrite.io/docs/client/storage) - Manage storage files. Read, create, delete, and preview files. Manipulate the preview of your files to fit your app perfectly. All files are scanned by ClamAV and stored in a secure and encrypted way. -* [**Functions**](https://appwrite.io/docs/server/functions) - Customize your Appwrite server by executing your custom code in a secure, isolated environment. You can trigger your code on any Appwrite system event, manually or using a CRON schedule. -* [**Realtime**](https://appwrite.io/docs/realtime) - Listen to real-time events for any of your Appwrite services including users, storage, functions, databases and more. -* [**Locale**](https://appwrite.io/docs/client/locale) - Track your user's location, and manage your app locale-based data. -* [**Avatars**](https://appwrite.io/docs/client/avatars) - Manage your users' avatars, countries' flags, browser icons, credit card symbols, and generate QR codes. +- [**Account**](https://appwrite.io/docs/client/account) - Manage current user authentication and account. Track and manage the user sessions, devices, sign-in methods, and security logs. +- [**Users**](https://appwrite.io/docs/server/users) - Manage and list all project users when in admin mode. +- [**Teams**](https://appwrite.io/docs/client/teams) - Manage and group users in teams. Manage memberships, invites, and user roles within a team. +- [**Databases**](https://appwrite.io/docs/client/databases) - Manage databases, collections and documents. Read, create, update, and delete documents and filter lists of document collections using advanced filters. +- [**Storage**](https://appwrite.io/docs/client/storage) - Manage storage files. Read, create, delete, and preview files. Manipulate the preview of your files to fit your app perfectly. All files are scanned by ClamAV and stored in a secure and encrypted way. +- [**Functions**](https://appwrite.io/docs/server/functions) - Customize your Appwrite server by executing your custom code in a secure, isolated environment. You can trigger your code on any Appwrite system event, manually or using a CRON schedule. +- [**Realtime**](https://appwrite.io/docs/realtime) - Listen to real-time events for any of your Appwrite services including users, storage, functions, databases and more. +- [**Locale**](https://appwrite.io/docs/client/locale) - Track your user's location, and manage your app locale-based data. +- [**Avatars**](https://appwrite.io/docs/client/avatars) - Manage your users' avatars, countries' flags, browser icons, credit card symbols, and generate QR codes. For the complete API documentation, visit [https://appwrite.io/docs](https://appwrite.io/docs). For more tutorials, news and announcements check out our [blog](https://medium.com/appwrite-io) and [Discord Server](https://discord.gg/GSeTUeA). @@ -153,34 +161,36 @@ For the complete API documentation, visit [https://appwrite.io/docs](https://app Below is a list of currently supported platforms and languages. If you wish to help us add support to your platform of choice, you can go over to our [SDK Generator](https://github.com/appwrite/sdk-generator) project and view our [contribution guide](https://github.com/appwrite/sdk-generator/blob/master/CONTRIBUTING.md). #### Client -* ✅   [Web](https://github.com/appwrite/sdk-for-web) (Maintained by the Appwrite Team) -* ✅   [Flutter](https://github.com/appwrite/sdk-for-flutter) (Maintained by the Appwrite Team) -* ✅   [Apple](https://github.com/appwrite/sdk-for-apple) - **Beta** (Maintained by the Appwrite Team) -* ✅   [Android](https://github.com/appwrite/sdk-for-android) (Maintained by the Appwrite Team) + +- ✅   [Web](https://github.com/appwrite/sdk-for-web) (Maintained by the Appwrite Team) +- ✅   [Flutter](https://github.com/appwrite/sdk-for-flutter) (Maintained by the Appwrite Team) +- ✅   [Apple](https://github.com/appwrite/sdk-for-apple) - **Beta** (Maintained by the Appwrite Team) +- ✅   [Android](https://github.com/appwrite/sdk-for-android) (Maintained by the Appwrite Team) #### Server -* ✅   [NodeJS](https://github.com/appwrite/sdk-for-node) (Maintained by the Appwrite Team) -* ✅   [PHP](https://github.com/appwrite/sdk-for-php) (Maintained by the Appwrite Team) -* ✅   [Dart](https://github.com/appwrite/sdk-for-dart) - (Maintained by the Appwrite Team) -* ✅   [Deno](https://github.com/appwrite/sdk-for-deno) - **Beta** (Maintained by the Appwrite Team) -* ✅   [Ruby](https://github.com/appwrite/sdk-for-ruby) (Maintained by the Appwrite Team) -* ✅   [Python](https://github.com/appwrite/sdk-for-python) (Maintained by the Appwrite Team) -* ✅   [Kotlin](https://github.com/appwrite/sdk-for-kotlin) - **Beta** (Maintained by the Appwrite Team) -* ✅   [Apple](https://github.com/appwrite/sdk-for-apple) - **Beta** (Maintained by the Appwrite Team) -* ✅   [.NET](https://github.com/appwrite/sdk-for-dotnet) - **Experimental** (Maintained by the Appwrite Team) + +- ✅   [NodeJS](https://github.com/appwrite/sdk-for-node) (Maintained by the Appwrite Team) +- ✅   [PHP](https://github.com/appwrite/sdk-for-php) (Maintained by the Appwrite Team) +- ✅   [Dart](https://github.com/appwrite/sdk-for-dart) - (Maintained by the Appwrite Team) +- ✅   [Deno](https://github.com/appwrite/sdk-for-deno) - **Beta** (Maintained by the Appwrite Team) +- ✅   [Ruby](https://github.com/appwrite/sdk-for-ruby) (Maintained by the Appwrite Team) +- ✅   [Python](https://github.com/appwrite/sdk-for-python) (Maintained by the Appwrite Team) +- ✅   [Kotlin](https://github.com/appwrite/sdk-for-kotlin) - **Beta** (Maintained by the Appwrite Team) +- ✅   [Apple](https://github.com/appwrite/sdk-for-apple) - **Beta** (Maintained by the Appwrite Team) +- ✅   [.NET](https://github.com/appwrite/sdk-for-dotnet) - **Experimental** (Maintained by the Appwrite Team) #### Community -* ✅   [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (Maintained by [Michael Gangolf](https://github.com/m1ga/)) -* ✅   [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (Maintained by [fenix-hub @GodotNuts](https://github.com/fenix-hub)) + +- ✅   [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (Maintained by [Michael Gangolf](https://github.com/m1ga/)) +- ✅   [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (Maintained by [fenix-hub @GodotNuts](https://github.com/fenix-hub)) Looking for more SDKs? - Help us by contributing a pull request to our [SDK Generator](https://github.com/appwrite/sdk-generator)! - ## Architecture ![Appwrite Architecture](docs/specs/overview.drawio.svg) -Appwrite uses a microservices architecture that was designed for easy scaling and delegation of responsibilities. In addition, Appwrite supports multiple APIs (REST, WebSocket, and GraphQL-soon) to allow you to interact with your resources leveraging your existing knowledge and protocols of choice. +Appwrite uses a microservices architecture that was designed for easy scaling and delegation of responsibilities. In addition, Appwrite supports multiple APIs (REST, WebSocket, and GraphQL-soon) to allow you to interact with your resources by leveraging your existing knowledge and protocols of choice. The Appwrite API layer was designed to be extremely fast by leveraging in-memory caching and delegating any heavy-lifting tasks to the Appwrite background workers. The background workers also allow you to precisely control your compute capacity and costs using a message queue to handle the load. You can learn more about our architecture in the [contribution guide](CONTRIBUTING.md#architecture-1). diff --git a/app/config/events.php b/app/config/events.php index 0a7d819142..6fe030d4bf 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -1,7 +1,7 @@ 'web', 'name' => 'Web', - 'version' => '10.0.0', + 'version' => '10.1.0', 'url' => 'https://github.com/appwrite/sdk-for-web', 'package' => 'https://www.npmjs.com/package/appwrite', 'enabled' => true, @@ -63,7 +63,7 @@ return [ [ 'key' => 'flutter', 'name' => 'Flutter', - 'version' => '8.0.0', + 'version' => '8.1.0', 'url' => 'https://github.com/appwrite/sdk-for-flutter', 'package' => 'https://pub.dev/packages/appwrite', 'enabled' => true, @@ -81,7 +81,7 @@ return [ [ 'key' => 'apple', 'name' => 'Apple', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-apple', 'package' => 'https://github.com/appwrite/sdk-for-apple', 'enabled' => true, @@ -116,7 +116,7 @@ return [ [ 'key' => 'android', 'name' => 'Android', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-android', 'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android', 'enabled' => true, @@ -162,7 +162,7 @@ return [ [ 'key' => 'web', 'name' => 'Console', - 'version' => '7.0.0', + 'version' => '7.1.0', 'url' => 'https://github.com/appwrite/sdk-for-console', 'package' => '', 'enabled' => true, @@ -180,7 +180,7 @@ return [ [ 'key' => 'cli', 'name' => 'Command Line', - 'version' => '1.0.0', + 'version' => '1.1.1', 'url' => 'https://github.com/appwrite/sdk-for-cli', 'package' => 'https://www.npmjs.com/package/appwrite-cli', 'enabled' => true, @@ -208,7 +208,7 @@ return [ [ 'key' => 'nodejs', 'name' => 'Node.js', - 'version' => '8.0.0', + 'version' => '8.1.0', 'url' => 'https://github.com/appwrite/sdk-for-node', 'package' => 'https://www.npmjs.com/package/node-appwrite', 'enabled' => true, @@ -226,7 +226,7 @@ return [ [ 'key' => 'deno', 'name' => 'Deno', - 'version' => '6.0.0', + 'version' => '6.1.0', 'url' => 'https://github.com/appwrite/sdk-for-deno', 'package' => 'https://deno.land/x/appwrite', 'enabled' => true, @@ -244,7 +244,7 @@ return [ [ 'key' => 'php', 'name' => 'PHP', - 'version' => '7.0.0', + 'version' => '7.1.0', 'url' => 'https://github.com/appwrite/sdk-for-php', 'package' => 'https://packagist.org/packages/appwrite/appwrite', 'enabled' => true, @@ -262,7 +262,7 @@ return [ [ 'key' => 'python', 'name' => 'Python', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-python', 'package' => 'https://pypi.org/project/appwrite/', 'enabled' => true, @@ -280,7 +280,7 @@ return [ [ 'key' => 'ruby', 'name' => 'Ruby', - 'version' => '7.0.0', + 'version' => '7.1.0', 'url' => 'https://github.com/appwrite/sdk-for-ruby', 'package' => 'https://rubygems.org/gems/appwrite', 'enabled' => true, @@ -298,7 +298,7 @@ return [ [ 'key' => 'go', 'name' => 'Go', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-go', 'package' => '', 'enabled' => false, @@ -316,7 +316,7 @@ return [ [ 'key' => 'java', 'name' => 'Java', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-java', 'package' => '', 'enabled' => false, @@ -334,7 +334,7 @@ return [ [ 'key' => 'dotnet', 'name' => '.NET', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-dotnet', 'package' => 'https://www.nuget.org/packages/Appwrite', 'enabled' => false, @@ -352,7 +352,7 @@ return [ [ 'key' => 'dart', 'name' => 'Dart', - 'version' => '7.0.0', + 'version' => '7.1.0', 'url' => 'https://github.com/appwrite/sdk-for-dart', 'package' => 'https://pub.dev/packages/dart_appwrite', 'enabled' => true, @@ -370,7 +370,7 @@ return [ [ 'key' => 'kotlin', 'name' => 'Kotlin', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-kotlin', 'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin', 'enabled' => true, @@ -392,7 +392,7 @@ return [ [ 'key' => 'swift', 'name' => 'Swift', - 'version' => '1.0.0', + 'version' => '1.1.0', 'url' => 'https://github.com/appwrite/sdk-for-swift', 'package' => 'https://github.com/appwrite/sdk-for-swift', 'enabled' => true, diff --git a/app/config/providers.php b/app/config/providers.php index 98ad93b30c..62430faae1 100644 --- a/app/config/providers.php +++ b/app/config/providers.php @@ -17,7 +17,7 @@ return [ // Ordered by ABC. 'icon' => 'icon-apple', 'enabled' => true, 'sandbox' => false, - 'form' => 'apple.phtml', // Perperation for adding ability to customized OAuth UI forms, currently handled hardcoded. + 'form' => 'apple.phtml', // Preparation for adding ability to customized OAuth UI forms, currently handled hardcoded. 'beta' => true, 'mock' => false, ], diff --git a/app/config/variables.php b/app/config/variables.php index 3eb11ad620..9f3bc018e8 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -413,7 +413,7 @@ return [ 'variables' => [ [ 'name' => '_APP_SMS_PROVIDER', - 'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'. \n\nAvailable providers are twilio, text-magic and telesign.", + 'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'. \n\nAvailable providers are twilio, text-magic, telesign, msg91, and vonage.", 'introduction' => '0.15.0', 'default' => '', 'required' => false, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index ef94b251c8..fb91a4517d 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -2,7 +2,6 @@ use Ahc\Jwt\JWT; use Appwrite\Auth\Auth; -use Appwrite\SMS\Adapter\Mock; use Appwrite\Auth\Validator\Password; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; @@ -930,7 +929,7 @@ App::post('/v1/account/sessions/phone') ]))); } - $secret = (App::getEnv('_APP_SMS_PROVIDER') === 'sms://mock') ? Mock::$digits : Auth::codeGenerator(); + $secret = Auth::codeGenerator(); $expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_PHONE); $token = new Document([ @@ -938,7 +937,7 @@ App::post('/v1/account/sessions/phone') 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'type' => Auth::TOKEN_TYPE_PHONE, - 'secret' => $secret, + 'secret' => Auth::hash($secret), 'expire' => $expire, 'userAgent' => $request->getUserAgent('UNKNOWN'), 'ip' => $request->getIP(), @@ -1418,7 +1417,7 @@ App::get('/v1/account/sessions/:sessionId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SESSION) - ->param('sessionId', null, new UID(), 'Session ID. Use the string \'current\' to get the current device session.') + ->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to get the current device session.') ->inject('response') ->inject('user') ->inject('locale') @@ -1696,7 +1695,7 @@ App::delete('/v1/account/sessions/:sessionId') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->label('abuse-limit', 100) - ->param('sessionId', null, new UID(), 'Session ID. Use the string \'current\' to delete the current device session.') + ->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to delete the current device session.') ->inject('request') ->inject('response') ->inject('user') @@ -1769,7 +1768,7 @@ App::patch('/v1/account/sessions/:sessionId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_SESSION) ->label('abuse-limit', 10) - ->param('sessionId', null, new UID(), 'Session ID. Use the string \'current\' to update the current device session.') + ->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to update the current device session.') ->inject('request') ->inject('response') ->inject('user') @@ -2258,7 +2257,7 @@ App::post('/v1/account/verification/phone') $isPrivilegedUser = Auth::isPrivilegedUser($roles); $isAppUser = Auth::isAppUser($roles); $verificationSecret = Auth::tokenGenerator(); - $secret = (App::getEnv('_APP_SMS_PROVIDER') === 'sms://mock') ? Mock::$digits : Auth::codeGenerator(); + $secret = Auth::codeGenerator(); $expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM); $verification = new Document([ @@ -2266,7 +2265,7 @@ App::post('/v1/account/verification/phone') 'userId' => $user->getId(), 'userInternalId' => $user->getInternalId(), 'type' => Auth::TOKEN_TYPE_PHONE, - 'secret' => $secret, + 'secret' => Auth::hash($secret), 'expire' => $expire, 'userAgent' => $request->getUserAgent('UNKNOWN'), 'ip' => $request->getIP(), diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index e2acb30772..5278abae3e 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -89,11 +89,11 @@ function createAttribute(string $databaseId, string $collectionId, Document $att } // Must throw here since dbForProject->createAttribute is performed by db worker - if ($required && $default) { + if ($required && isset($default)) { throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for required attribute'); } - if ($array && $default) { + if ($array && isset($default)) { throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for array attributes'); } @@ -1783,7 +1783,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') @@ -1856,7 +1856,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') ->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.') ->param('data', [], new JSON(), 'Document data as JSON object.') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true) ->inject('response') @@ -2074,8 +2074,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('documentId', null, new UID(), 'Document ID.') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('documentId', '', new UID(), 'Document ID.') ->inject('response') ->inject('dbForProject') ->inject('mode') @@ -2137,7 +2137,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->label('sdk.response.model', Response::MODEL_LOG_LIST) ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID.') - ->param('documentId', null, new UID(), 'Document ID.') + ->param('documentId', '', new UID(), 'Document ID.') ->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true) ->inject('response') ->inject('dbForProject') @@ -2243,8 +2243,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID.') - ->param('documentId', null, new UID(), 'Document ID.') + ->param('collectionId', '', new UID(), 'Collection ID.') + ->param('documentId', '', new UID(), 'Document ID.') ->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true) ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true) ->inject('response') @@ -2376,8 +2376,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') - ->param('documentId', null, new UID(), 'Document ID.') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('documentId', '', new UID(), 'Document ID.') ->inject('response') ->inject('dbForProject') ->inject('events') @@ -2534,7 +2534,7 @@ App::get('/v1/databases/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } @@ -2648,7 +2648,7 @@ App::get('/v1/databases/:databaseId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } @@ -2763,7 +2763,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index f42d1059e0..d3a26b414e 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -71,8 +71,13 @@ App::post('/v1/functions') ->param('enabled', true, new Boolean(), 'Is function enabled?', true) ->inject('response') ->inject('dbForProject') + ->inject('project') + ->inject('user') ->inject('events') - ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Event $eventsInstance) { + ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) { + + $cron = !empty($schedule) ? new CronExpression($schedule) : null; + $next = !empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null; $functionId = ($functionId == 'unique()') ? ID::unique() : $functionId; $function = $dbForProject->createDocument('functions', new Document([ @@ -86,11 +91,22 @@ App::post('/v1/functions') 'schedule' => $schedule, 'scheduleUpdatedAt' => DateTime::now(), 'schedulePrevious' => null, - 'scheduleNext' => null, + 'scheduleNext' => $next, 'timeout' => $timeout, 'search' => implode(' ', [$functionId, $name, $runtime]) ])); + if ($next) { + // Async task reschedule + $functionEvent = new Func(); + $functionEvent + ->setFunction($function) + ->setType('schedule') + ->setUser($user) + ->setProject($project) + ->schedule(new \DateTime($next)); + } + $eventsInstance->setParam('functionId', $function->getId()); $response @@ -281,7 +297,7 @@ App::get('/v1/functions/:functionId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } @@ -384,7 +400,7 @@ App::get('/v1/functions/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } @@ -442,11 +458,9 @@ App::put('/v1/functions/:functionId') throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $original = $function->getAttribute('schedule', ''); - $cron = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null; - $next = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null; + $cron = !empty($schedule) ? new CronExpression($schedule) : null; + $next = !empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null; - $scheduleUpdatedAt = $schedule !== $original ? DateTime::now() : $function->getAttribute('scheduleUpdatedAt'); $enabled ??= $function->getAttribute('enabled', true); $function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [ @@ -454,14 +468,14 @@ App::put('/v1/functions/:functionId') 'name' => $name, 'events' => $events, 'schedule' => $schedule, - 'scheduleUpdatedAt' => $scheduleUpdatedAt, + 'scheduleUpdatedAt' => DateTime::now(), 'scheduleNext' => $next, 'timeout' => $timeout, 'enabled' => $enabled, 'search' => implode(' ', [$functionId, $name, $function->getAttribute('runtime')]), ]))); - if ($next && $schedule !== $original) { + if ($next) { // Async task reschedule $functionEvent = new Func(); $functionEvent @@ -519,24 +533,10 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') throw new Exception(Exception::BUILD_NOT_READY); } - $schedule = $function->getAttribute('schedule', ''); - $cron = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null; - $next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null; - $function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [ - 'deployment' => $deployment->getId(), - 'scheduleNext' => $next, + 'deployment' => $deployment->getId() ]))); - if ($next) { // Init first schedule - $functionEvent = new Func(); - $functionEvent - ->setType('schedule') - ->setFunction($function) - ->setProject($project) - ->schedule(new \DateTime($next)); - } - $events ->setParam('functionId', $function->getId()) ->setParam('deploymentId', $deployment->getId()); @@ -935,6 +935,67 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') $response->noContent(); }); +App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') + ->groups(['api', 'functions']) + ->desc('Create Build') + ->label('scope', 'functions.write') + ->label('event', 'functions.[functionId].deployments.[deploymentId].update') + ->label('audits.event', 'deployment.update') + ->label('audits.resource', 'function/{request.functionId}') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'functions') + ->label('sdk.method', 'createBuild') + ->label('sdk.description', '/docs/references/functions/create-build.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('functionId', '', new UID(), 'Function ID.') + ->param('deploymentId', '', new UID(), 'Deployment ID.') + ->param('buildId', '', new UID(), 'Build unique ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('project') + ->inject('events') + ->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) { + + $function = $dbForProject->getDocument('functions', $functionId); + $deployment = $dbForProject->getDocument('deployments', $deploymentId); + + if ($function->isEmpty()) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } + + if ($deployment->isEmpty()) { + throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); + } + + $build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $buildId)); + + if ($build->isEmpty()) { + throw new Exception(Exception::BUILD_NOT_FOUND); + } + + if ($build->getAttribute('status') !== 'failed') { + throw new Exception(Exception::BUILD_IN_PROGRESS, 'Build not failed'); + } + + $events + ->setParam('functionId', $function->getId()) + ->setParam('deploymentId', $deployment->getId()); + + // Retry the build + $buildEvent = new Build(); + $buildEvent + ->setType(BUILD_TYPE_RETRY) + ->setResource($function) + ->setDeployment($deployment) + ->setProject($project) + ->trigger(); + + $response->noContent(); + }); + + + App::post('/v1/functions/:functionId/executions') ->groups(['api', 'functions']) ->desc('Create Execution') @@ -1066,21 +1127,21 @@ App::post('/v1/functions/:functionId/executions') } $vars = array_reduce($function['vars'] ?? [], function (array $carry, Document $var) { - $carry[$var->getAttribute('key')] = $var->getAttribute('value'); + $carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? ''; return $carry; }, []); $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_ID' => $function->getId(), - 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''), + 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'), 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(), - 'APPWRITE_FUNCTION_TRIGGER' => 'http', - 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'], - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'], - 'APPWRITE_FUNCTION_DATA' => $data, 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), - 'APPWRITE_FUNCTION_USER_ID' => $user->getId(), - 'APPWRITE_FUNCTION_JWT' => $jwt, + 'APPWRITE_FUNCTION_TRIGGER' => 'http', + 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '', + 'APPWRITE_FUNCTION_DATA' => $data ?? '', + 'APPWRITE_FUNCTION_USER_ID' => $user->getId() ?? '', + 'APPWRITE_FUNCTION_JWT' => $jwt ?? '', ]); /** Execute function */ @@ -1258,65 +1319,6 @@ App::get('/v1/functions/:functionId/executions/:executionId') $response->dynamic($execution, Response::MODEL_EXECUTION); }); -App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') - ->groups(['api', 'functions']) - ->desc('Retry Build') - ->label('scope', 'functions.write') - ->label('event', 'functions.[functionId].deployments.[deploymentId].update') - ->label('audits.event', 'deployment.update') - ->label('audits.resource', 'function/{request.functionId}') - ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) - ->label('sdk.namespace', 'functions') - ->label('sdk.method', 'retryBuild') - ->label('sdk.description', '/docs/references/functions/retry-build.md') - ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) - ->label('sdk.response.model', Response::MODEL_NONE) - ->param('functionId', '', new UID(), 'Function ID.') - ->param('deploymentId', '', new UID(), 'Deployment ID.') - ->param('buildId', '', new UID(), 'Build unique ID.') - ->inject('response') - ->inject('dbForProject') - ->inject('project') - ->inject('events') - ->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) { - - $function = $dbForProject->getDocument('functions', $functionId); - $deployment = $dbForProject->getDocument('deployments', $deploymentId); - - if ($function->isEmpty()) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } - - if ($deployment->isEmpty()) { - throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); - } - - $build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $buildId)); - - if ($build->isEmpty()) { - throw new Exception(Exception::BUILD_NOT_FOUND); - } - - if ($build->getAttribute('status') !== 'failed') { - throw new Exception(Exception::BUILD_IN_PROGRESS, 'Build not failed'); - } - - $events - ->setParam('functionId', $function->getId()) - ->setParam('deploymentId', $deployment->getId()); - - // Retry the build - $buildEvent = new Build(); - $buildEvent - ->setType(BUILD_TYPE_RETRY) - ->setResource($function) - ->setDeployment($deployment) - ->setProject($project) - ->trigger(); - - $response->noContent(); - }); - // Variables App::post('/v1/functions/:functionId/variables') @@ -1332,7 +1334,7 @@ App::post('/v1/functions/:functionId/variables') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE) - ->param('functionId', null, new UID(), 'Function unique ID.', false) + ->param('functionId', '', new UID(), 'Function unique ID.', false) ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) ->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', false) ->inject('response') @@ -1384,7 +1386,7 @@ App::get('/v1/functions/:functionId/variables') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE_LIST) - ->param('functionId', null, new UID(), 'Function unique ID.', false) + ->param('functionId', '', new UID(), 'Function unique ID.', false) ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, Response $response, Database $dbForProject) { @@ -1411,8 +1413,8 @@ App::get('/v1/functions/:functionId/variables/:variableId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE) - ->param('functionId', null, new UID(), 'Function unique ID.', false) - ->param('variableId', null, new UID(), 'Variable unique ID.', false) + ->param('functionId', '', new UID(), 'Function unique ID.', false) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, string $variableId, Response $response, Database $dbForProject) { @@ -1447,8 +1449,8 @@ App::put('/v1/functions/:functionId/variables/:variableId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE) - ->param('functionId', null, new UID(), 'Function unique ID.', false) - ->param('variableId', null, new UID(), 'Variable unique ID.', false) + ->param('functionId', '', new UID(), 'Function unique ID.', false) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) ->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', true) ->inject('response') @@ -1499,8 +1501,8 @@ App::delete('/v1/functions/:functionId/variables/:variableId') ->label('sdk.description', '/docs/references/functions/delete-variable.md') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('functionId', null, new UID(), 'Function unique ID.', false) - ->param('variableId', null, new UID(), 'Variable unique ID.', false) + ->param('functionId', '', new UID(), 'Function unique ID.', false) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) ->inject('response') ->inject('dbForProject') ->action(function (string $functionId, string $variableId, Response $response, Database $dbForProject) { diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 5c8ba8a268..bfea863d29 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -330,7 +330,7 @@ App::get('/v1/projects/:projectId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } @@ -584,7 +584,7 @@ App::post('/v1/projects/:projectId/webhooks') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_WEBHOOK) - ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') ->param('url', null, new URL(['http', 'https']), 'Webhook URL.') @@ -672,8 +672,8 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_WEBHOOK) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('webhookId', null, new UID(), 'Webhook unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('webhookId', '', new UID(), 'Webhook unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { @@ -706,8 +706,8 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_WEBHOOK) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('webhookId', null, new UID(), 'Webhook unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('webhookId', '', new UID(), 'Webhook unique ID.') ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') ->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') ->param('url', null, new URL(['http', 'https']), 'Webhook URL.') @@ -760,8 +760,8 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_WEBHOOK) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('webhookId', null, new UID(), 'Webhook unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('webhookId', '', new UID(), 'Webhook unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { @@ -798,8 +798,8 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') ->label('sdk.method', 'deleteWebhook') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('webhookId', null, new UID(), 'Webhook unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('webhookId', '', new UID(), 'Webhook unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { @@ -838,7 +838,7 @@ App::post('/v1/projects/:projectId/keys') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_KEY) - ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) @@ -888,7 +888,7 @@ App::get('/v1/projects/:projectId/keys') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_KEY_LIST) - ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, Response $response, Database $dbForConsole) { @@ -920,8 +920,8 @@ App::get('/v1/projects/:projectId/keys/:keyId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_KEY) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('keyId', null, new UID(), 'Key unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('keyId', '', new UID(), 'Key unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) { @@ -954,8 +954,8 @@ App::put('/v1/projects/:projectId/keys/:keyId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_KEY) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('keyId', null, new UID(), 'Key unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('keyId', '', new UID(), 'Key unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') ->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true) @@ -1000,8 +1000,8 @@ App::delete('/v1/projects/:projectId/keys/:keyId') ->label('sdk.method', 'deleteKey') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('keyId', null, new UID(), 'Key unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('keyId', '', new UID(), 'Key unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) { @@ -1040,7 +1040,7 @@ App::post('/v1/projects/:projectId/platforms') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PLATFORM) - ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') ->param('type', null, new WhiteList([Origin::CLIENT_TYPE_WEB, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_LINUX, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_APPLE_IOS, Origin::CLIENT_TYPE_APPLE_MACOS, Origin::CLIENT_TYPE_APPLE_WATCHOS, Origin::CLIENT_TYPE_APPLE_TVOS, Origin::CLIENT_TYPE_ANDROID, Origin::CLIENT_TYPE_UNITY], true), 'Platform type.') ->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.') ->param('key', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true) @@ -1122,8 +1122,8 @@ App::get('/v1/projects/:projectId/platforms/:platformId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PLATFORM) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('platformId', null, new UID(), 'Platform unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('platformId', '', new UID(), 'Platform unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) { @@ -1156,8 +1156,8 @@ App::put('/v1/projects/:projectId/platforms/:platformId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PLATFORM) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('platformId', null, new UID(), 'Platform unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('platformId', '', new UID(), 'Platform unique ID.') ->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.') ->param('key', '', new Text(256), 'Package name for android or bundle ID for iOS. Max length: 256 chars.', true) ->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true) @@ -1203,8 +1203,8 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') ->label('sdk.method', 'deletePlatform') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('platformId', null, new UID(), 'Platform unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('platformId', '', new UID(), 'Platform unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) { @@ -1243,7 +1243,7 @@ App::post('/v1/projects/:projectId/domains') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOMAIN) - ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') ->param('domain', null, new DomainValidator(), 'Domain name.') ->inject('response') ->inject('dbForConsole') @@ -1340,8 +1340,8 @@ App::get('/v1/projects/:projectId/domains/:domainId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOMAIN) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('domainId', null, new UID(), 'Domain unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('domainId', '', new UID(), 'Domain unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { @@ -1374,8 +1374,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOMAIN) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('domainId', null, new UID(), 'Domain unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('domainId', '', new UID(), 'Domain unique ID.') ->inject('response') ->inject('dbForConsole') ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) { @@ -1433,8 +1433,8 @@ App::delete('/v1/projects/:projectId/domains/:domainId') ->label('sdk.method', 'deleteDomain') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('projectId', null, new UID(), 'Project unique ID.') - ->param('domainId', null, new UID(), 'Domain unique ID.') + ->param('projectId', '', new UID(), 'Project unique ID.') + ->param('domainId', '', new UID(), 'Domain unique ID.') ->inject('response') ->inject('dbForConsole') ->inject('deletes') diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 1134887fb6..f236285749 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -346,7 +346,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FILE) - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('file', [], new File(), 'Binary file.', false) ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true) @@ -667,7 +667,7 @@ App::get('/v1/storage/buckets/:bucketId/files') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FILE_LIST) - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') @@ -744,7 +744,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FILE) - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->inject('response') ->inject('dbForProject') @@ -793,7 +793,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE) ->label('sdk.methodType', 'location') - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID') ->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true) ->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true) @@ -959,7 +959,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', '*/*') ->label('sdk.methodType', 'location') - ->param('bucketId', null, new UID(), 'Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->inject('request') ->inject('response') @@ -1099,7 +1099,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', '*/*') ->label('sdk.methodType', 'location') - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->inject('response') ->inject('request') @@ -1256,7 +1256,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_FILE) - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File unique ID.') ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission string. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true) ->inject('response') @@ -1358,7 +1358,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->label('sdk.description', '/docs/references/storage/delete-file.md') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) - ->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') + ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new UID(), 'File ID.') ->inject('response') ->inject('dbForProject') @@ -1518,7 +1518,7 @@ App::get('/v1/storage/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } @@ -1629,7 +1629,7 @@ App::get('/v1/storage/:bucketId/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index c975370223..a42b9d317e 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -553,7 +553,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') ->label('sdk.description', '/docs/references/teams/get-team-member.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST) + ->label('sdk.response.model', Response::MODEL_MEMBERSHIP) ->param('teamId', '', new UID(), 'Team ID.') ->param('membershipId', '', new UID(), 'Membership ID.') ->inject('response') @@ -865,7 +865,7 @@ App::get('/v1/teams/:teamId/logs') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_LOG_LIST) - ->param('teamId', null, new UID(), 'Team ID.') + ->param('teamId', '', new UID(), 'Team ID.') ->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true) ->inject('response') ->inject('dbForProject') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index c83f03d96e..407bc1eaab 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -290,10 +290,10 @@ App::post('/v1/users/scrypt') ->param('email', '', new Email(), 'User email.') ->param('password', '', new Password(), 'User password hashed using Scrypt.') ->param('passwordSalt', '', new Text(128), 'Optional salt used to hash password.') - ->param('passwordCpu', '', new Integer(), 'Optional CPU cost used to hash password.') - ->param('passwordMemory', '', new Integer(), 'Optional memory cost used to hash password.') - ->param('passwordParallel', '', new Integer(), 'Optional parallelization cost used to hash password.') - ->param('passwordLength', '', new Integer(), 'Optional hash length used to hash password.') + ->param('passwordCpu', 8, new Integer(), 'Optional CPU cost used to hash password.') + ->param('passwordMemory', 14, new Integer(), 'Optional memory cost used to hash password.') + ->param('passwordParallel', 1, new Integer(), 'Optional parallelization cost used to hash password.') + ->param('passwordLength', 64, new Integer(), 'Optional hash length used to hash password.') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') ->inject('dbForProject') @@ -981,7 +981,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('userId', '', new UID(), 'User ID.') - ->param('sessionId', null, new UID(), 'Session ID.') + ->param('sessionId', '', new UID(), 'Session ID.') ->inject('response') ->inject('dbForProject') ->inject('events') @@ -1176,7 +1176,7 @@ App::get('/v1/users/usage') }; $stats[$metric][] = [ 'value' => 0, - 'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff), + 'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)), ]; $backfill--; } diff --git a/app/init.php b/app/init.php index 3c9f785f9d..a19492394b 100644 --- a/app/init.php +++ b/app/init.php @@ -94,8 +94,8 @@ const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate period in seconds const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours -const APP_CACHE_BUSTER = 500; -const APP_VERSION_STABLE = '1.0.1'; +const APP_CACHE_BUSTER = 501; +const APP_VERSION_STABLE = '1.0.3'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; @@ -1028,7 +1028,7 @@ App::setResource('sms', function () { $secret = $dsn->getPassword(); return match ($dsn->getHost()) { - 'mock' => new Mock('', ''), // used for tests + 'mock' => new Mock($user, $secret), // used for tests 'twilio' => new Twilio($user, $secret), 'text-magic' => new TextMagic($user, $secret), 'telesign' => new Telesign($user, $secret), diff --git a/app/views/console/comps/permissions-matrix.phtml b/app/views/console/comps/permissions-matrix.phtml index 836b0843ad..e912f26629 100644 --- a/app/views/console/comps/permissions-matrix.phtml +++ b/app/views/console/comps/permissions-matrix.phtml @@ -81,6 +81,8 @@ $escapedPermissions = \array_map(function ($perm) { list="types" type="text" x-model="permission.role" + @keydown.enter="prevent($event)" + @keydown="clearPermission(index)" @keyup="updatePermission(index)"/> diff --git a/app/views/console/functions/function.phtml b/app/views/console/functions/function.phtml index 80806fed56..c98e092a0e 100644 --- a/app/views/console/functions/function.phtml +++ b/app/views/console/functions/function.phtml @@ -391,9 +391,9 @@ sort($patterns); Created - Status - Trigger - Runtime + Status + Trigger + Runtime @@ -422,11 +422,11 @@ sort($patterns);
- + - +