Merge pull request #1 from appwrite/0.7.x

0.7.x
This commit is contained in:
Bradley Schofield
2020-09-19 14:50:18 +01:00
committed by GitHub
206 changed files with 5856 additions and 2621 deletions
+62
View File
@@ -0,0 +1,62 @@
name: "CodeQL"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 16 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['javascript']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
+10
View File
@@ -22,6 +22,14 @@
- Added pagination for projects list on the console home page.
- Updated storage calculation to match IEC standards
- Now using Alpine as base Docker image
- User name max length is now 128 chars and not 100 for better API consistency
- Team name max length is now 128 chars and not 100 for better API consistency
- Collection name max length is now 128 chars and not 256 for better API consistency
- Project name max length is now 128 chars and not 100 for better API consistency
- Webhook name max length is now 128 chars and not 256 for better API consistency
- API Key name max length is now 128 chars and not 256 for better API consistency
- Task name max length is now 128 chars and not 256 for better API consistency
- Platform name max length is now 128 chars and not 256 for better API consistency
- New and consistent response format for all API object + new response examples in the docs
- Removed user roles attribute from user object (can be fetched from /v1/teams/memberships) **
- Removed type attribute from session object response (used only internally)
@@ -59,6 +67,8 @@
- Access to Health API now requires authentication with an API Key with access to `health.read` scope allowed
- Added option to force HTTPS connection to the Appwrite server (_APP_OPTIONS_FORCE_HTTPS)
- Now using your `_APP_SYSTEM_EMAIL_ADDRESS` as the email address for issuing and renewing SSL certificates
- Block iframe access to Appwrite console using the `X-Frame-Options` header.
- Fixed `roles` param input validator
# Version 0.6.2 (PRE-RELEASE)
+69 -63
View File
@@ -6,38 +6,48 @@ We would ❤️ for you to contribute to Appwrite and help make it better! We wa
If you are worried or dont know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or [@appwrite_io](https://twitter.com/appwrite_io) on Twitter, and anyone from the [Appwrite team on Discord](https://discord.gg/GSeTUeA). You can also submit an issue, and a maintainer can guide you!
## Where to Start?
Pull requests are great, but there are many other areas where you can help Appwrite.
### Blogging & Speaking
Blogging, speaking about, or creating tutorials about one of Appwrites many features. Mention [@appwrite_io](https://twitter.com/appwrite_io) on Twitter and/or email team [at] appwrite [dot] io so we can give pointers and tips and help you spread the word by promoting your content on the different Appwrite communication channels. Please add your blog posts and videos of talks to our [Awesome Appwrite]() repo on GitHub.
### Presenting at Meetups
Presenting at meetups and conferences about your Appwrite projects. Your unique challenges and successes in building things with Appwrite can provide great speaking material. Wed love to review your talk abstract/CFP, so get in touch with us if youd like some help!
### Sending Feedbacks & Reporting Bugs
Sending feedback is a great way for us to understand your different use cases of Appwrite better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
### Submitting New Ideas
If you think Appwrite could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
### Improving Documentation
Submitting documentation updates, enhancements, designs, or bug fixes. Spelling or grammar fixes will be very much appreciated.
### Helping Someone
Searching for Appwrite on Discord, GitHub or StackOverflow and helping someone else who needs help. You can also help by reaching others how to contribute to Appwrite's repo!
## Code of Conduct
Help us keep Appwrite open and inclusive. Please read and follow our [Code of Conduct](/CODE_OF_CONDUCT.md).
## Setup From Source
To set up a working **development environment**, just fork the project git repository and install the backend and frontend dependencies using the proper package manager and create run the docker-compose stack.
> If you just want to install Appwrite for day-to-day usage and not as a code maintainer use this [installation guide](https://github.com/appwrite/appwrite#installation).
Please note that these instructions are for setting a functional dev environment. If you want to set up an Appwrite instance to integrate into your app, you should probably try and install Appwrite by using the instructions in the [getting started guide](https://appwrite.io/docs/getting-started-for-web) or in the main [README](README.md) file.
```bash
git clone git@github.com:[YOUR_FORK_HERE]/appwrite.git
cd appwrite
docker-compose up -d
```
After finishing the installation process, you can start writing and editing code. To compile new CSS and JS distribution files, use 'less' and 'build' tasks using gulp as a task manager.
## Architecture
Appwrite's current structure is a combination of both [Monolithic](https://en.wikipedia.org/wiki/Monolithic_application) and [Microservice](https://en.wikipedia.org/wiki/Microservices) architectures, but our final goal, as we grow, is to be using only microservices.
---
![Appwrite](docs/specs/overview.drawio.svg)
---
### The Monolithic Part
Appwrite's main API container is designed as a monolithic app. This is a decision we made to allow us to develop the project faster while still being a very small team.
Although the Appwrite API is a monolithic app, it has a very clear separation of concern as each internal service or worker is separated by its container, which will allow us as we grow to start breaking services for better maintenance and scalability.
### The Microservice Part
Each container in Appwrite is a microservice on its own. Each service is an independent process that can scale without regard to any of the other services.
Currently, all of the Appwrite microservices are intended to communicate using the TCP protocol over a private network. You should be aware to not expose any of the services to the public-facing network, besides the public port 80 and 443, who, by default, are used to expose the Appwrite HTTP API.
## Technology Stack
To start helping us to improve the Appwrite server by submitting code, prior knowledge of Appwrite's technology stack can help you with getting started.
@@ -74,7 +84,7 @@ We use prettier for our JS coding standards and for auto-formatting our code.
Appwrite is built to scale. Please keep in mind that the Appwrite stack can run in different environments and different scales.
We wish Appwrite will be as easy to set up and in a single, localhost, and easy to grow to a large environment with thousands and even hundreds of instances.
We wish Appwrite will be as easy to set up and in a single, localhost, and easy to grow to a large environment with dozens and even hundreds of instances.
When contributing code, please take into account the following considerations:
@@ -87,22 +97,6 @@ When contributing code, please take into account the following considerations:
* Background Jobs
* Task Execution Time
## Architecture
Appwrite's current structure is a combination of both [Monolithic](https://en.wikipedia.org/wiki/Monolithic_application) and [Microservice](https://en.wikipedia.org/wiki/Microservices) architectures, but our final goal, as we grow, is to be using only microservices.
### The Monolithic Part
Appwrite's main API container is designed as a monolithic app. This is a decision we made to allow us to develop the project faster while still being a very small team.
Although the Appwrite API is a monolithic app, it has a very clear separation of concern as each internal service or worker is separated by its container, which will allow us as we grow to start breaking services for better maintenance and scalability.
### The Microservice Part
Each container in Appwrite is a microservice on its own. Each service is an independent process that can scale without regard to any of the other services.
Currently, all of the Appwrite microservices are intended to communicate using the TCP protocol over a private network. You should be aware to not expose any of the services to the public-facing network, besides the public port 80 and 443, who, by default, are used to expose the Appwrite HTTP API.
## Security & Privacy
Security and privacy are extremely important to Appwrite, developers, and users alike. Make sure to follow the best industry standards and practices.
@@ -123,24 +117,6 @@ This will allow the Appwrite community to have sufficient discussion about the n
This is also important for the Appwrite lead developers to be able to give technical input and different emphasize regarding the feature design and architecture.
## Setup From Source
To set up a working **development environment**, just fork the project git repository and install the backend and frontend dependencies using the proper package manager and create run the docker-compose stack.
> If you just want to install Appwrite for day-to-day usage and not as a code maintainer use this [installation guide](https://github.com/appwrite/appwrite#installation).
Please note that these instructions are for setting a functional dev environment. If you want to set up an Appwrite instance to integrate into your app, you should probably try and install Appwrite by using the instructions in the [getting started guide](https://appwrite.io/docs/getting-started-for-web) or in the main [README](README.md) file.
```bash
git clone git@github.com:[YOUR_FORK_HERE]/appwrite.git
cd appwrite
docker-compose up -d
```
After finishing the installation process, you can start writing and editing code. To compile new CSS and JS distribution files, use 'less' and 'build' tasks using gulp as a task manager.
## Build
To build a new version of the Appwrite server, all you need to do is run the build.sh file like this:
@@ -213,3 +189,33 @@ From time to time, our team will add tutorials that will help contributors find
* [Adding Support for a New OAuth2 Provider](./docs/tutorials/add-oauth2-provider.md)
* [Appwrite Environment Variables](./docs/tutorials/environment-variables.md)
* [Running in Production](./docs/tutorials/running-in-production.md)
## Other Ways to Help
Pull requests are great, but there are many other areas where you can help Appwrite.
### Blogging & Speaking
Blogging, speaking about, or creating tutorials about one of Appwrites many features. Mention [@appwrite_io](https://twitter.com/appwrite_io) on Twitter and/or email team [at] appwrite [dot] io so we can give pointers and tips and help you spread the word by promoting your content on the different Appwrite communication channels. Please add your blog posts and videos of talks to our [Awesome Appwrite]() repo on GitHub.
### Presenting at Meetups
Presenting at meetups and conferences about your Appwrite projects. Your unique challenges and successes in building things with Appwrite can provide great speaking material. Wed love to review your talk abstract/CFP, so get in touch with us if youd like some help!
### Sending Feedbacks & Reporting Bugs
Sending feedback is a great way for us to understand your different use cases of Appwrite better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
### Submitting New Ideas
If you think Appwrite could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
### Improving Documentation
Submitting documentation updates, enhancements, designs, or bug fixes. Spelling or grammar fixes will be very much appreciated.
### Helping Someone
Searching for Appwrite on Discord, GitHub or StackOverflow and helping someone else who needs help. You can also help by reaching others how to contribute to Appwrite's repo!
+1 -1
View File
@@ -16,7 +16,7 @@ FROM php:7.4-cli-alpine as step1
ENV TZ=Asia/Tel_Aviv \
PHP_REDIS_VERSION=5.3.0 \
PHP_SWOOLE_VERSION=4.5.2 \
PHP_SWOOLE_VERSION=4.5.3 \
PHP_XDEBUG_VERSION=sdebug_2_9-beta
RUN \
-178
View File
@@ -1,178 +0,0 @@
FROM composer:2.0 as step0
ARG TESTING=false
ENV TESTING=$TESTING
WORKDIR /usr/local/src/
COPY composer.lock /usr/local/src/
COPY composer.json /usr/local/src/
RUN composer update --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM php:8.0.0alpha1-cli-alpine as step1
ENV TZ=Asia/Tel_Aviv \
DEBIAN_FRONTEND=noninteractive \
PHP_REDIS_VERSION=5.3.0 \
PHP_SWOOLE_VERSION=4.5.2 \
PHP_XDEBUG_VERSION=sdebug_2_9-beta
RUN \
apk update && \
apk add ca-certificates gcc make g++ autoconf wget git openssl make zip unzip brotli zlib
RUN docker-php-ext-install sockets
RUN \
# Redis Extension
wget -q https://github.com/phpredis/phpredis/archive/$PHP_REDIS_VERSION.tar.gz && \
tar -xf $PHP_REDIS_VERSION.tar.gz && \
cd phpredis-$PHP_REDIS_VERSION && \
phpize && \
./configure && \
make && make install && \
cd .. && \
## Swoole Extension
git clone https://github.com/swoole/swoole-src.git && \
cd swoole-src && \
#git checkout v$PHP_SWOOLE_VERSION && \
phpize && \
./configure --enable-sockets --enable-http2 && \
make && make install && \
cd ..
## XDebug Extension
# git clone https://github.com/swoole/sdebug.git && \
# cd sdebug && \
# git checkout $PHP_XDEBUG_VERSION && \
# phpize && \
# ./configure --enable-xdebug && \
# make clean && make && make install
# cd .. && \
# Meminfo Extension
# git clone https://github.com/BitOne/php-meminfo.git && \
# cd php-meminfo && \
# git checkout v1.0.5 && \
# cd extension/php7 && \
# phpize && \
# ./configure --enable-meminfo && \
# make && make install
FROM php:8.0.0alpha1-cli-alpine as final
LABEL maintainer="team@appwrite.io"
ARG VERSION=dev
ENV TZ=Asia/Tel_Aviv \
DEBIAN_FRONTEND=noninteractive \
_APP_SERVER=swoole \
_APP_ENV=production \
_APP_DOMAIN=localhost \
_APP_DOMAIN_TARGET=localhost \
_APP_HOME=https://appwrite.io \
_APP_EDITION=community \
_APP_OPTIONS_ABUSE=enabled \
_APP_OPTIONS_FORCE_HTTPS=disabled \
_APP_OPENSSL_KEY_V1=your-secret-key \
_APP_STORAGE_LIMIT=100000000 \
_APP_STORAGE_ANTIVIRUS=enabled \
_APP_REDIS_HOST=redis \
_APP_REDIS_PORT=6379 \
_APP_DB_HOST=mariadb \
_APP_DB_PORT=3306 \
_APP_DB_USER=root \
_APP_DB_PASS=password \
_APP_DB_SCHEMA=appwrite \
_APP_INFLUXDB_HOST=influxdb \
_APP_INFLUXDB_PORT=8086 \
_APP_STATSD_HOST=telegraf \
_APP_STATSD_PORT=8125 \
_APP_SMTP_HOST=smtp \
_APP_SMTP_PORT=25 \
_APP_SETUP=self-hosted \
_APP_VERSION=$VERSION
#ENV _APP_SMTP_SECURE ''
#ENV _APP_SMTP_USERNAME ''
#ENV _APP_SMTP_PASSWORD ''
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN \
apk update && \
apk add libwebp certbot htop procps \
oniguruma libcurl imagemagick-libs yaml-dev brotli-libs zlib-dev
# pecl install imagick yaml && \
# docker-php-ext-enable imagick yaml
RUN docker-php-ext-install sockets curl opcache pdo pdo_mysql
WORKDIR /usr/src/code
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190128/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20190128/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190128/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20190128/
# COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190128/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20190128/
# COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190128/meminfo.so /usr/local/lib/php/extensions/no-debug-non-zts-20190128/
# Add Source Code
COPY ./app /usr/src/code/app
COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs
COPY ./public /usr/src/code/public
COPY ./src /usr/src/code/src
# Set Volumes
RUN mkdir -p /storage/uploads && \
mkdir -p /storage/cache && \
mkdir -p /storage/config && \
mkdir -p /storage/certificates && \
mkdir -p /storage/functions && \
mkdir -p /storage/debug && \
chown -Rf www-data.www-data /storage/uploads && chmod -Rf 0755 /storage/uploads && \
chown -Rf www-data.www-data /storage/cache && chmod -Rf 0755 /storage/cache && \
chown -Rf www-data.www-data /storage/config && chmod -Rf 0755 /storage/config && \
chown -Rf www-data.www-data /storage/certificates && chmod -Rf 0755 /storage/certificates && \
chown -Rf www-data.www-data /storage/functions && chmod -Rf 0755 /storage/functions && \
chown -Rf www-data.www-data /storage/debug && chmod -Rf 0755 /storage/debug
# Executables
RUN chmod +x /usr/local/bin/doctor
RUN chmod +x /usr/local/bin/migrate
RUN chmod +x /usr/local/bin/schedule
RUN chmod +x /usr/local/bin/test
RUN chmod +x /usr/local/bin/worker-audits
RUN chmod +x /usr/local/bin/worker-certificates
RUN chmod +x /usr/local/bin/worker-deletes
RUN chmod +x /usr/local/bin/worker-functions
RUN chmod +x /usr/local/bin/worker-mails
RUN chmod +x /usr/local/bin/worker-tasks
RUN chmod +x /usr/local/bin/worker-usage
RUN chmod +x /usr/local/bin/worker-webhooks
# Letsencrypt Permissions
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini
RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini
# RUN echo zend_extension=xdebug.so >> /usr/local/etc/php/conf.d/xdebug.ini
# RUN echo extension=meminfo.so >> /usr/local/etc/php/conf.d/meminfo.ini
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.enable_cli = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_enable = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_output_dir = /tmp/" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_enable_trigger = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.trace_format = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
EXPOSE 80
#, "-dxdebug.auto_trace=1"
#, "-dxdebug.profiler_enable=1"
#, "-dopcache.preload=opcache.preload=/usr/src/code/app/preload.php"
CMD [ "php", "app/server.php", "-dopcache.preload=opcache.preload=/usr/src/code/app/preload.php" ]
-180
View File
@@ -1,180 +0,0 @@
FROM composer:2.0 as step0
ARG TESTING=false
ENV TESTING=$TESTING
WORKDIR /usr/local/src/
COPY composer.lock /usr/local/src/
COPY composer.json /usr/local/src/
RUN composer update --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM php:7.4-cli as step1
ENV TZ=Asia/Tel_Aviv \
DEBIAN_FRONTEND=noninteractive \
PHP_REDIS_VERSION=5.3.0 \
PHP_SWOOLE_VERSION=4.5.2 \
PHP_XDEBUG_VERSION=sdebug_2_9-beta
RUN \
apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests ca-certificates software-properties-common wget git openssl make zip unzip libbrotli-dev libz-dev
RUN docker-php-ext-install sockets
RUN \
# Redis Extension
wget -q https://github.com/phpredis/phpredis/archive/$PHP_REDIS_VERSION.tar.gz && \
tar -xf $PHP_REDIS_VERSION.tar.gz && \
cd phpredis-$PHP_REDIS_VERSION && \
phpize && \
./configure && \
make && make install && \
cd .. && \
## Swoole Extension
git clone https://github.com/swoole/swoole-src.git && \
cd swoole-src && \
git checkout v$PHP_SWOOLE_VERSION && \
phpize && \
./configure --enable-sockets --enable-http2 && \
make && make install && \
cd ..
## XDebug Extension
# git clone https://github.com/swoole/sdebug.git && \
# cd sdebug && \
# git checkout $PHP_XDEBUG_VERSION && \
# phpize && \
# ./configure --enable-xdebug && \
# make clean && make && make install
# cd .. && \
# Meminfo Extension
# git clone https://github.com/BitOne/php-meminfo.git && \
# cd php-meminfo && \
# git checkout v1.0.5 && \
# cd extension/php7 && \
# phpize && \
# ./configure --enable-meminfo && \
# make && make install
FROM php:7.4-cli as final
LABEL maintainer="team@appwrite.io"
ARG VERSION=dev
ENV TZ=Asia/Tel_Aviv \
DEBIAN_FRONTEND=noninteractive \
_APP_SERVER=swoole \
_APP_ENV=production \
_APP_DOMAIN=localhost \
_APP_DOMAIN_TARGET=localhost \
_APP_HOME=https://appwrite.io \
_APP_EDITION=community \
_APP_OPTIONS_ABUSE=enabled \
_APP_OPTIONS_FORCE_HTTPS=disabled \
_APP_OPENSSL_KEY_V1=your-secret-key \
_APP_STORAGE_LIMIT=100000000 \
_APP_STORAGE_ANTIVIRUS=enabled \
_APP_REDIS_HOST=redis \
_APP_REDIS_PORT=6379 \
_APP_DB_HOST=mariadb \
_APP_DB_PORT=3306 \
_APP_DB_USER=root \
_APP_DB_PASS=password \
_APP_DB_SCHEMA=appwrite \
_APP_INFLUXDB_HOST=influxdb \
_APP_INFLUXDB_PORT=8086 \
_APP_STATSD_HOST=telegraf \
_APP_STATSD_PORT=8125 \
_APP_SMTP_HOST=smtp \
_APP_SMTP_PORT=25 \
_APP_FUNCTIONS_TIMEOUT=900 \
_APP_FUNCTIONS_CONTAINERS=10 \
_APP_SETUP=self-hosted \
_APP_VERSION=$VERSION
#ENV _APP_SMTP_SECURE ''
#ENV _APP_SMTP_USERNAME ''
#ENV _APP_SMTP_PASSWORD ''
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN \
apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests webp certbot htop procps docker.io \
libonig-dev libcurl4-gnutls-dev libmagickwand-dev libyaml-dev libbrotli-dev libz-dev && \
pecl install imagick yaml && \
docker-php-ext-enable imagick yaml
RUN docker-php-ext-install sockets curl opcache pdo pdo_mysql
WORKDIR /usr/src/code
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
# COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
# COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/meminfo.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
# Add Source Code
COPY ./app /usr/src/code/app
COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs
COPY ./public /usr/src/code/public
COPY ./src /usr/src/code/src
# Set Volumes
RUN mkdir -p /storage/uploads && \
mkdir -p /storage/cache && \
mkdir -p /storage/config && \
mkdir -p /storage/certificates && \
mkdir -p /storage/functions && \
mkdir -p /storage/debug && \
chown -Rf www-data.www-data /storage/uploads && chmod -Rf 0755 /storage/uploads && \
chown -Rf www-data.www-data /storage/cache && chmod -Rf 0755 /storage/cache && \
chown -Rf www-data.www-data /storage/config && chmod -Rf 0755 /storage/config && \
chown -Rf www-data.www-data /storage/certificates && chmod -Rf 0755 /storage/certificates && \
chown -Rf www-data.www-data /storage/functions && chmod -Rf 0755 /storage/functions && \
chown -Rf www-data.www-data /storage/debug && chmod -Rf 0755 /storage/debug
# Executables
RUN chmod +x /usr/local/bin/doctor
RUN chmod +x /usr/local/bin/migrate
RUN chmod +x /usr/local/bin/schedule
RUN chmod +x /usr/local/bin/test
RUN chmod +x /usr/local/bin/worker-audits
RUN chmod +x /usr/local/bin/worker-certificates
RUN chmod +x /usr/local/bin/worker-deletes
RUN chmod +x /usr/local/bin/worker-functions
RUN chmod +x /usr/local/bin/worker-mails
RUN chmod +x /usr/local/bin/worker-tasks
RUN chmod +x /usr/local/bin/worker-usage
RUN chmod +x /usr/local/bin/worker-webhooks
# Letsencrypt Permissions
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini
RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini
# RUN echo zend_extension=xdebug.so >> /usr/local/etc/php/conf.d/xdebug.ini
# RUN echo extension=meminfo.so >> /usr/local/etc/php/conf.d/meminfo.ini
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.enable_cli = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_enable = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_output_dir = /tmp/" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_enable_trigger = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.trace_format = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
EXPOSE 80
#, "-dxdebug.auto_trace=1"
#, "-dxdebug.profiler_enable=1"
#, "-dopcache.preload=opcache.preload=/usr/src/code/app/preload.php"
CMD [ "php", "app/server.php", "-dopcache.preload=opcache.preload=/usr/src/code/app/preload.php" ]
-178
View File
@@ -1,178 +0,0 @@
FROM composer:2.0 as step0
ARG TESTING=false
ENV TESTING=$TESTING
WORKDIR /usr/local/src/
COPY composer.lock /usr/local/src/
COPY composer.json /usr/local/src/
RUN composer update --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM php:8.0-rc as step1
ENV TZ=Asia/Tel_Aviv \
DEBIAN_FRONTEND=noninteractive \
PHP_REDIS_VERSION=5.3.0 \
PHP_SWOOLE_VERSION=4.5.2 \
PHP_XDEBUG_VERSION=sdebug_2_9-beta
RUN \
apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests ca-certificates software-properties-common wget git openssl make zip unzip libbrotli-dev libz-dev
RUN docker-php-ext-install sockets
RUN \
# Redis Extension
wget -q https://github.com/phpredis/phpredis/archive/$PHP_REDIS_VERSION.tar.gz && \
tar -xf $PHP_REDIS_VERSION.tar.gz && \
cd phpredis-$PHP_REDIS_VERSION && \
phpize && \
./configure && \
make && make install && \
cd .. && \
## Swoole Extension
git clone https://github.com/swoole/swoole-src.git && \
cd swoole-src && \
#git checkout v$PHP_SWOOLE_VERSION && \
phpize && \
./configure --enable-sockets --enable-http2 && \
make && make install && \
cd ..
## XDebug Extension
# git clone https://github.com/swoole/sdebug.git && \
# cd sdebug && \
# git checkout $PHP_XDEBUG_VERSION && \
# phpize && \
# ./configure --enable-xdebug && \
# make clean && make && make install
# cd .. && \
# Meminfo Extension
# git clone https://github.com/BitOne/php-meminfo.git && \
# cd php-meminfo && \
# git checkout v1.0.5 && \
# cd extension/php7 && \
# phpize && \
# ./configure --enable-meminfo && \
# make && make install
FROM php:8.0-rc as final
LABEL maintainer="team@appwrite.io"
ARG VERSION=dev
ENV TZ=Asia/Tel_Aviv \
DEBIAN_FRONTEND=noninteractive \
_APP_SERVER=swoole \
_APP_ENV=production \
_APP_DOMAIN=localhost \
_APP_DOMAIN_TARGET=localhost \
_APP_HOME=https://appwrite.io \
_APP_EDITION=community \
_APP_OPTIONS_ABUSE=enabled \
_APP_OPTIONS_FORCE_HTTPS=disabled \
_APP_OPENSSL_KEY_V1=your-secret-key \
_APP_STORAGE_LIMIT=100000000 \
_APP_STORAGE_ANTIVIRUS=enabled \
_APP_REDIS_HOST=redis \
_APP_REDIS_PORT=6379 \
_APP_DB_HOST=mariadb \
_APP_DB_PORT=3306 \
_APP_DB_USER=root \
_APP_DB_PASS=password \
_APP_DB_SCHEMA=appwrite \
_APP_INFLUXDB_HOST=influxdb \
_APP_INFLUXDB_PORT=8086 \
_APP_STATSD_HOST=telegraf \
_APP_STATSD_PORT=8125 \
_APP_SMTP_HOST=smtp \
_APP_SMTP_PORT=25 \
_APP_SETUP=self-hosted \
_APP_VERSION=$VERSION
#ENV _APP_SMTP_SECURE ''
#ENV _APP_SMTP_USERNAME ''
#ENV _APP_SMTP_PASSWORD ''
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN \
apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests webp certbot htop procps \
libonig-dev libcurl4-gnutls-dev libmagickwand-dev libyaml-dev libbrotli-dev libz-dev
# pecl install imagick yaml && \
# docker-php-ext-enable imagick yaml
RUN docker-php-ext-install sockets curl opcache pdo pdo_mysql
WORKDIR /usr/src/code
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
# COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
# COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/meminfo.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
# Add Source Code
COPY ./app /usr/src/code/app
COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs
COPY ./public /usr/src/code/public
COPY ./src /usr/src/code/src
# Set Volumes
RUN mkdir -p /storage/uploads && \
mkdir -p /storage/cache && \
mkdir -p /storage/config && \
mkdir -p /storage/certificates && \
mkdir -p /storage/functions && \
mkdir -p /storage/debug && \
chown -Rf www-data.www-data /storage/uploads && chmod -Rf 0755 /storage/uploads && \
chown -Rf www-data.www-data /storage/cache && chmod -Rf 0755 /storage/cache && \
chown -Rf www-data.www-data /storage/config && chmod -Rf 0755 /storage/config && \
chown -Rf www-data.www-data /storage/certificates && chmod -Rf 0755 /storage/certificates && \
chown -Rf www-data.www-data /storage/functions && chmod -Rf 0755 /storage/functions && \
chown -Rf www-data.www-data /storage/debug && chmod -Rf 0755 /storage/debug
# Executables
RUN chmod +x /usr/local/bin/doctor
RUN chmod +x /usr/local/bin/migrate
RUN chmod +x /usr/local/bin/schedule
RUN chmod +x /usr/local/bin/test
RUN chmod +x /usr/local/bin/worker-audits
RUN chmod +x /usr/local/bin/worker-certificates
RUN chmod +x /usr/local/bin/worker-deletes
RUN chmod +x /usr/local/bin/worker-functions
RUN chmod +x /usr/local/bin/worker-mails
RUN chmod +x /usr/local/bin/worker-tasks
RUN chmod +x /usr/local/bin/worker-usage
RUN chmod +x /usr/local/bin/worker-webhooks
# Letsencrypt Permissions
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini
RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini
# RUN echo zend_extension=xdebug.so >> /usr/local/etc/php/conf.d/xdebug.ini
# RUN echo extension=meminfo.so >> /usr/local/etc/php/conf.d/meminfo.ini
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.enable_cli = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_enable = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_output_dir = /tmp/" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.profiler_enable_trigger = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
# RUN echo "xdebug.trace_format = 1" >> /usr/local/etc/php/conf.d/appwrite.ini
EXPOSE 80
#, "-dxdebug.auto_trace=1"
#, "-dxdebug.profiler_enable=1"
#, "-dopcache.preload=opcache.preload=/usr/src/code/app/preload.php"
CMD [ "php", "app/server.php", "-dopcache.preload=opcache.preload=/usr/src/code/app/preload.php" ]
+5 -2
View File
@@ -2,12 +2,12 @@
<a href="https://appwrite.io" target="_blank"><img width="260" height="39" src="https://appwrite.io/images/github-logo.png" alt="Appwrite Logo"></a>
<br />
<br />
<b>A complete backend solution for your [Flutter / Vue / Angular / React / iOS / Android / *ANY OTHER*] client app</b>
<b>A complete backend solution for your [Flutter / Vue / Angular / React / iOS / Android / *ANY OTHER*] app</b>
<br />
<br />
</p>
[![Hacktoberfest](https://badgen.net/badge/hacktoberfest/friendly/pink)](CONTRIBUTING.md)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord)](https://discord.gg/GSeTUeA)
[![Docker Pulls](https://badgen.net/docker/pulls/appwrite/appwrite)](https://travis-ci.org/appwrite/appwrite)
[![Travis CI](https://badgen.net/travis/appwrite/appwrite?label=build)](https://travis-ci.org/appwrite/appwrite)
@@ -51,6 +51,7 @@ The easiest way to start running your Appwrite server is by running our docker-c
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:0.7.0
```
@@ -62,6 +63,7 @@ docker run -it --rm \
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:0.7.0
```
@@ -71,6 +73,7 @@ docker run -it --rm ^
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:0.7.0
```
+14
View File
@@ -0,0 +1,14 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| < 0.5 | :x: |
| 0.6.x | :white_check_mark: |
| 0.7.x | :white_check_mark: |
| 0.8.0 | :white_check_mark: |
## Reporting a Vulnerability
For security issues, kindly email us security@appwrite.io instead of posting a public issue in GitHub.
+10
View File
@@ -656,6 +656,7 @@ $collections = [
'default' => '',
'required' => false,
'array' => false,
'filter' => ['encrypt'],
],
],
],
@@ -826,6 +827,7 @@ $collections = [
'default' => '',
'required' => false,
'array' => false,
'filter' => ['encrypt'],
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
@@ -1433,6 +1435,13 @@ $collections = [
],
],
],
Database::SYSTEM_COLLECTION_RESERVED => [
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
'$id' => Database::SYSTEM_COLLECTION_RESERVED,
'$permissions' => ['read' => ['*']],
'name' => 'Reserved',
'structure' => true,
],
];
/*
@@ -1461,6 +1470,7 @@ foreach ($providers as $index => $provider) {
'default' => '',
'required' => false,
'array' => false,
'filter' => ['encrypt'],
];
$collections[Database::SYSTEM_COLLECTION_USERS]['rules'][] = [
+2 -2
View File
@@ -30,7 +30,7 @@ return [
[
'key' => 'flutter',
'name' => 'Flutter',
'version' => '0.2.3',
'version' => '0.3.0-dev.2',
'url' => 'https://github.com/appwrite/sdk-for-flutter',
'enabled' => true,
'beta' => true,
@@ -45,7 +45,7 @@ return [
[
'key' => 'flutter-dev',
'name' => 'Flutter (Dev Channel)',
'version' => '0.2.3',
'version' => '0.3.2',
'url' => 'https://github.com/appwrite/sdk-for-flutter-dev',
'enabled' => true,
'beta' => true,
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+32 -32
View File
@@ -51,9 +51,9 @@ App::post('/v1/account')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/account/create.md')
->label('abuse-limit', 10)
->param('email', '', function () { return new Email(); }, 'User email.')
->param('password', '', function () { return new Password(); }, 'User password. Must be between 6 to 32 chars.')
->param('name', '', function () { return new Text(100); }, 'User name.', true)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->action(function ($email, $password, $name, $request, $response, $project, $projectDB, $webhooks, $audits) use ($oauth2Keys) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -157,8 +157,8 @@ App::post('/v1/account/sessions')
->label('sdk.description', '/docs/references/account/create-session.md')
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('email', '', function () { return new Email(); }, 'User email.')
->param('password', '', function () { return new Password(); }, 'User password. Must be between 6 to 32 chars.')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->action(function ($email, $password, $request, $response, $projectDB, $webhooks, $audits) {
/** @var Appwrite\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
@@ -256,10 +256,10 @@ App::get('/v1/account/sessions/oauth2/:provider')
->label('sdk.methodType', 'webAuth')
->label('abuse-limit', 50)
->label('abuse-key', 'ip:{ip}')
->param('provider', '', function () { return new WhiteList(\array_keys(Config::getParam('providers'))); }, 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('providers'), function($node) {return (!$node['mock']);}))).'.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('providers'), function($node) {return (!$node['mock']);}))).'.')
->param('success', $oauthDefaultSuccess, function ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
->param('failure', $oauthDefaultFailure, function ($clients) { return new Host($clients); }, 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
->param('scopes', [], function () { return new ArrayList(new Text(128)); }, 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes.', true)
->param('scopes', [], new ArrayList(new Text(128)), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes.', true)
->action(function ($provider, $success, $failure, $scopes, $request, $response, $project) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -301,10 +301,10 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
->label('error', __DIR__.'/../../views/general/error.phtml')
->label('scope', 'public')
->label('docs', false)
->param('projectId', '', function () { return new Text(1024); }, 'Project unique ID.')
->param('provider', '', function () { return new WhiteList(\array_keys(Config::getParam('providers'))); }, 'OAuth2 provider.')
->param('code', '', function () { return new Text(1024); }, 'OAuth2 code.')
->param('state', '', function () { return new Text(2048); }, 'Login state params.', true)
->param('projectId', '', new Text(1024), 'Project unique ID.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
->param('code', '', new Text(1024), 'OAuth2 code.')
->param('state', '', new Text(2048), 'Login state params.', true)
->action(function ($projectId, $provider, $code, $state, $request, $response) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -326,10 +326,10 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
->label('scope', 'public')
->label('origin', '*')
->label('docs', false)
->param('projectId', '', function () { return new Text(1024); }, 'Project unique ID.')
->param('provider', '', function () { return new WhiteList(\array_keys(Config::getParam('providers'))); }, 'OAuth2 provider.')
->param('code', '', function () { return new Text(1024); }, 'OAuth2 code.')
->param('state', '', function () { return new Text(2048); }, 'Login state params.', true)
->param('projectId', '', new Text(1024), 'Project unique ID.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
->param('code', '', new Text(1024), 'OAuth2 code.')
->param('state', '', new Text(2048), 'Login state params.', true)
->action(function ($projectId, $provider, $code, $state, $request, $response) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -353,9 +353,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
->label('abuse-limit', 50)
->label('abuse-key', 'ip:{ip}')
->label('docs', false)
->param('provider', '', function () { return new WhiteList(\array_keys(Config::getParam('providers'))); }, 'OAuth2 provider.')
->param('code', '', function () { return new Text(1024); }, 'OAuth2 code.')
->param('state', '', function () { return new Text(2048); }, 'OAuth2 state params.', true)
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
->param('code', '', new Text(1024), 'OAuth2 code.')
->param('state', '', new Text(2048), 'OAuth2 state params.', true)
->action(function ($provider, $code, $state, $request, $response, $project, $user, $projectDB, $audits) use ($oauthDefaultSuccess) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -738,7 +738,7 @@ App::patch('/v1/account/name')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateName')
->label('sdk.description', '/docs/references/account/update-name.md')
->param('name', '', function () { return new Text(100); }, 'User name.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.')
->action(function ($name, $response, $user, $projectDB, $audits) use ($oauth2Keys) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@@ -779,8 +779,8 @@ App::patch('/v1/account/password')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updatePassword')
->label('sdk.description', '/docs/references/account/update-password.md')
->param('password', '', function () { return new Password(); }, 'New user password. Must be between 6 to 32 chars.')
->param('oldPassword', '', function () { return new Password(); }, 'Old user password. Must be between 6 to 32 chars.')
->param('password', '', new Password(), 'New user password. Must be between 6 to 32 chars.')
->param('oldPassword', '', new Password(), 'Old user password. Must be between 6 to 32 chars.')
->action(function ($password, $oldPassword, $response, $user, $projectDB, $audits) use ($oauth2Keys) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@@ -825,8 +825,8 @@ App::patch('/v1/account/email')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateEmail')
->label('sdk.description', '/docs/references/account/update-email.md')
->param('email', '', function () { return new Email(); }, 'User email.')
->param('password', '', function () { return new Password(); }, 'User password. Must be between 6 to 32 chars.')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->action(function ($email, $password, $response, $user, $projectDB, $audits) use ($oauth2Keys) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@@ -885,7 +885,7 @@ App::patch('/v1/account/prefs')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updatePrefs')
->param('prefs', '', function () { return new Assoc();}, 'Prefs key-value JSON object.')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->label('sdk.description', '/docs/references/account/update-prefs.md')
->action(function ($prefs, $response, $user, $projectDB, $audits) {
/** @var Utopia\Response $response */
@@ -992,7 +992,7 @@ App::delete('/v1/account/sessions/:sessionId')
->label('sdk.method', 'deleteSession')
->label('sdk.description', '/docs/references/account/delete-session.md')
->label('abuse-limit', 100)
->param('sessionId', null, function () { return new UID(); }, 'Session unique ID. Use the string \'current\' to delete the current device session.')
->param('sessionId', null, new UID(), 'Session unique ID. Use the string \'current\' to delete the current device session.')
->action(function ($sessionId, $request, $response, $user, $projectDB, $audits, $webhooks) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -1113,7 +1113,7 @@ App::post('/v1/account/recovery')
->label('sdk.description', '/docs/references/account/create-recovery.md')
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('email', '', function () { return new Email(); }, 'User email.')
->param('email', '', new Email(), 'User email.')
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients'])
->action(function ($email, $url, $request, $response, $projectDB, $project, $locale, $mails, $audits) {
/** @var Utopia\Request $request */
@@ -1219,10 +1219,10 @@ App::put('/v1/account/recovery')
->label('sdk.description', '/docs/references/account/update-recovery.md')
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('userId', '', function () { return new UID(); }, 'User account UID address.')
->param('secret', '', function () { return new Text(256); }, 'Valid reset token.')
->param('password', '', function () { return new Password(); }, 'New password. Must be between 6 to 32 chars.')
->param('passwordAgain', '', function () {return new Password(); }, 'New password again. Must be between 6 to 32 chars.')
->param('userId', '', new UID(), 'User account UID address.')
->param('secret', '', new Text(256), 'Valid reset token.')
->param('password', '', new Password(), 'New password. Must be between 6 to 32 chars.')
->param('passwordAgain', '', new Password(), 'New password again. Must be between 6 to 32 chars.')
->action(function ($userId, $secret, $password, $passwordAgain, $response, $projectDB, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -1386,8 +1386,8 @@ App::put('/v1/account/verification')
->label('sdk.description', '/docs/references/account/update-verification.md')
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('secret', '', function () { return new Text(256); }, 'Valid verification token.')
->param('userId', '', new UID(), 'User unique ID.')
->param('secret', '', new Text(256), 'Valid verification token.')
->action(function ($userId, $secret, $response, $user, $projectDB, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
+25 -25
View File
@@ -90,10 +90,10 @@ App::get('/v1/avatars/credit-cards/:code')
->label('sdk.method', 'getCreditCard')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-credit-card.md')
->param('code', '', function () { return new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))); }, 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.')
->param('width', 100, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', 100, function () { return new Range(0, 100); }, 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.')
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->action(function ($code, $width, $height, $quality, $response) use ($avatarCallback) {
return $avatarCallback('credit-cards', $code, $width, $height, $quality, $response);
}, ['response']);
@@ -107,10 +107,10 @@ App::get('/v1/avatars/browsers/:code')
->label('sdk.method', 'getBrowser')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-browser.md')
->param('code', '', function () { return new WhiteList(\array_keys(Config::getParam('avatar-browsers'))); }, 'Browser Code.')
->param('width', 100, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', 100, function () { return new Range(0, 100); }, 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-browsers'))), 'Browser Code.')
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->action(function ($code, $width, $height, $quality, $response) use ($avatarCallback) {
return $avatarCallback('browsers', $code, $width, $height, $quality, $response);
}, ['response']);
@@ -124,10 +124,10 @@ App::get('/v1/avatars/flags/:code')
->label('sdk.method', 'getFlag')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-flag.md')
->param('code', '', function () { return new WhiteList(\array_keys(Config::getParam('avatar-flags'))); }, 'Country Code. ISO Alpha-2 country code format.')
->param('width', 100, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', 100, function () { return new Range(0, 100); }, 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-flags'))), 'Country Code. ISO Alpha-2 country code format.')
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->action(function ($code, $width, $height, $quality, $response) use ($avatarCallback) {
return $avatarCallback('flags', $code, $width, $height, $quality, $response);
}, ['response']);
@@ -141,9 +141,9 @@ App::get('/v1/avatars/image')
->label('sdk.method', 'getImage')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-image.md')
->param('url', '', function () { return new URL(); }, 'Image URL which you want to crop.')
->param('width', 400, function () { return new Range(0, 2000); }, 'Resize preview image width, Pass an integer between 0 to 2000.', true)
->param('height', 400, function () { return new Range(0, 2000); }, 'Resize preview image height, Pass an integer between 0 to 2000.', true)
->param('url', '', new URL(), 'Image URL which you want to crop.')
->param('width', 400, new Range(0, 2000), 'Resize preview image width, Pass an integer between 0 to 2000.', true)
->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000.', true)
->action(function ($url, $width, $height, $response) {
/** @var Utopia\Response $response */
@@ -207,7 +207,7 @@ App::get('/v1/avatars/favicon')
->label('sdk.method', 'getFavicon')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-favicon.md')
->param('url', '', function () { return new URL(); }, 'Website URL which you want to fetch the favicon from.')
->param('url', '', new URL(), 'Website URL which you want to fetch the favicon from.')
->action(function ($url, $response) {
/** @var Utopia\Response $response */
@@ -357,10 +357,10 @@ App::get('/v1/avatars/qr')
->label('sdk.method', 'getQR')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-qr.md')
->param('text', '', function () { return new Text(512); }, 'Plain text to be converted to QR code image.')
->param('size', 400, function () { return new Range(0, 1000); }, 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true)
->param('margin', 1, function () { return new Range(0, 10); }, 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true)
->param('download', false, function () { return new Boolean(true); }, 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true)
->param('text', '', new Text(512), 'Plain text to be converted to QR code image.')
->param('size', 400, new Range(0, 1000), 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true)
->param('margin', 1, new Range(0, 10), 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true)
->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true)
->action(function ($text, $size, $margin, $download, $response) {
/** @var Utopia\Response $response */
@@ -393,11 +393,11 @@ App::get('/v1/avatars/initials')
->label('sdk.method', 'getInitials')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-initials.md')
->param('name', '', function () { return new Text(512); }, 'Full Name. When empty, current user name or email will be used.', true)
->param('width', 500, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 500, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('color', '', function () { return new HexColor(); }, 'Changes text color. By default a random color will be picked and stay will persistent to the given name.', true)
->param('background', '', function () { return new HexColor(); }, 'Changes background color. By default a random color will be picked and stay will persistent to the given name.', true)
->param('name', '', new Text(128), 'Full Name. When empty, current user name or email will be used. Max length: 128 chars.', true)
->param('width', 500, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 500, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('color', '', new HexColor(), 'Changes text color. By default a random color will be picked and stay will persistent to the given name.', true)
->param('background', '', new HexColor(), 'Changes background color. By default a random color will be picked and stay will persistent to the given name.', true)
->action(function ($name, $width, $height, $color, $background, $response, $user) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
+44 -44
View File
@@ -30,9 +30,9 @@ App::post('/v1/database/collections')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'createCollection')
->label('sdk.description', '/docs/references/database/create-collection.md')
->param('name', '', function () { return new Text(256); }, 'Collection name.')
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('rules', [], function ($projectDB) { return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]])); }, 'Array of [rule objects](/docs/rules). Each rule define a collection field name, data type and validation.', false, ['projectDB'])
->action(function ($name, $read, $write, $rules, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
@@ -66,7 +66,7 @@ App::post('/v1/database/collections')
'rules' => $parsedRules,
]);
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
throw new Exception('Unauthorized permissions', 401);
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
@@ -106,10 +106,10 @@ App::get('/v1/database/collections')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'listCollections')
->label('sdk.description', '/docs/references/database/list-collections.md')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 40000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 40000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -137,7 +137,7 @@ App::get('/v1/database/collections/:collectionId')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'getCollection')
->label('sdk.description', '/docs/references/database/get-collection.md')
->param('collectionId', '', function () { return new UID(); }, 'Collection unique ID.')
->param('collectionId', '', new UID(), 'Collection unique ID.')
->action(function ($collectionId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -159,7 +159,7 @@ App::get('/v1/database/collections/:collectionId')
// ->label('sdk.namespace', 'database')
// ->label('sdk.method', 'getCollectionLogs')
// ->label('sdk.description', '/docs/references/database/get-collection-logs.md')
// ->param('collectionId', '', function () { return new UID(); }, 'Collection unique ID.')
// ->param('collectionId', '', new UID(), 'Collection unique ID.')
// ->action(
// function ($collectionId) use ($response, $register, $projectDB, $project) {
// $collection = $projectDB->getDocument($collectionId, false);
@@ -225,10 +225,10 @@ App::put('/v1/database/collections/:collectionId')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'updateCollection')
->label('sdk.description', '/docs/references/database/update-collection.md')
->param('collectionId', '', function () { return new UID(); }, 'Collection unique ID.')
->param('name', null, function () { return new Text(256); }, 'Collection name.')
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions(/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('collectionId', '', new UID(), 'Collection unique ID.')
->param('name', null, new Text(128), 'Collection name. Max length: 128 chars.')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions(/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('rules', [], function ($projectDB) { return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]])); }, 'Array of [rule objects](/docs/rules). Each rule define a collection field name, data type and validation.', true, ['projectDB'])
->action(function ($collectionId, $name, $read, $write, $rules, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
@@ -266,7 +266,7 @@ App::put('/v1/database/collections/:collectionId')
'rules' => $parsedRules,
]));
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
throw new Exception('Unauthorized permissions', 401);
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
@@ -301,7 +301,7 @@ App::delete('/v1/database/collections/:collectionId')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'deleteCollection')
->label('sdk.description', '/docs/references/database/delete-collection.md')
->param('collectionId', '', function () { return new UID(); }, 'Collection unique ID.')
->param('collectionId', '', new UID(), 'Collection unique ID.')
->action(function ($collectionId, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -342,13 +342,13 @@ App::post('/v1/database/collections/:collectionId/documents')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'createDocument')
->label('sdk.description', '/docs/references/database/create-document.md')
->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('data', [], function () { return new JSON(); }, 'Document data as JSON object.')
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('parentDocument', '', function () { return new UID(); }, 'Parent document unique ID. Use when you want your new document to be a child of a parent document.', true)
->param('parentProperty', '', function () { return new Key(); }, 'Parent document property name. Use when you want your new document to be a child of a parent document.', true)
->param('parentPropertyType', Document::SET_TYPE_ASSIGN, function () { return new WhiteList([Document::SET_TYPE_ASSIGN, Document::SET_TYPE_APPEND, Document::SET_TYPE_PREPEND]); }, 'Parent document property connection type. You can set this value to **assign**, **append** or **prepend**, default value is assign. Use when you want your new document to be a child of a parent document.', true)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('data', [], new JSON(), 'Document data as JSON object.')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('parentDocument', '', new UID(), 'Parent document unique ID. Use when you want your new document to be a child of a parent document.', true)
->param('parentProperty', '', new Key(), 'Parent document property name. Use when you want your new document to be a child of a parent document.', true)
->param('parentPropertyType', Document::SET_TYPE_ASSIGN, new WhiteList([Document::SET_TYPE_ASSIGN, Document::SET_TYPE_APPEND, Document::SET_TYPE_PREPEND], true), 'Parent document property connection type. You can set this value to **assign**, **append** or **prepend**, default value is assign. Use when you want your new document to be a child of a parent document.', true)
->action(function ($collectionId, $data, $read, $write, $parentDocument, $parentProperty, $parentPropertyType, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -404,7 +404,7 @@ App::post('/v1/database/collections/:collectionId/documents')
$authorization = new Authorization($parentDocument, 'write');
if (!$authorization->isValid($new->getPermissions())) {
throw new Exception('Unauthorized action', 401);
throw new Exception('Unauthorized permissions', 401);
}
$parentDocument
@@ -429,7 +429,7 @@ App::post('/v1/database/collections/:collectionId/documents')
try {
$data = $projectDB->createDocument($data);
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
throw new Exception('Unauthorized permissions', 401);
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
@@ -465,14 +465,14 @@ App::get('/v1/database/collections/:collectionId/documents')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'listDocuments')
->label('sdk.description', '/docs/references/database/list-documents.md')
->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('filters', [], function () { return new ArrayList(new Text(128)); }, 'Array of filter strings. Each filter is constructed from a key name, comparison operator (=, !=, >, <, <=, >=) and a value. You can also use a dot (.) separator in attribute names to filter by child document attributes. Examples: \'name=John Doe\' or \'category.$id>=5bed2d152c362\'.', true)
->param('limit', 25, function () { return new Range(0, 1000); }, 'Maximum number of documents to return in response. Use this value to manage pagination.', true)
->param('offset', 0, function () { return new Range(0, 900000000); }, 'Offset value. Use this value to manage pagination.', true)
->param('orderField', '$id', function () { return new Text(128); }, 'Document field that results will be sorted by.', true)
->param('orderType', 'ASC', function () { return new WhiteList(array('DESC', 'ASC')); }, 'Order direction. Possible values are DESC for descending order, or ASC for ascending order.', true)
->param('orderCast', 'string', function () { return new WhiteList(array('int', 'string', 'date', 'time', 'datetime')); }, 'Order field type casting. Possible values are int, string, date, time or datetime. The database will attempt to cast the order field to the value you pass here. The default value is a string.', true)
->param('search', '', function () { return new Text(256); }, 'Search query. Enter any free text search. The database will try to find a match against all document attributes and children.', true)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('filters', [], new ArrayList(new Text(128)), 'Array of filter strings. Each filter is constructed from a key name, comparison operator (=, !=, >, <, <=, >=) and a value. You can also use a dot (.) separator in attribute names to filter by child document attributes. Examples: \'name=John Doe\' or \'category.$id>=5bed2d152c362\'.', true)
->param('limit', 25, new Range(0, 1000), 'Maximum number of documents to return in response. Use this value to manage pagination.', true)
->param('offset', 0, new Range(0, 900000000), 'Offset value. Use this value to manage pagination.', true)
->param('orderField', '$id', new Text(128), 'Document field that results will be sorted by.', true)
->param('orderType', 'ASC', new WhiteList(['DESC', 'ASC'], true), 'Order direction. Possible values are DESC for descending order, or ASC for ascending order.', true)
->param('orderCast', 'string', new WhiteList(['int', 'string', 'date', 'time', 'datetime'], true), 'Order field type casting. Possible values are int, string, date, time or datetime. The database will attempt to cast the order field to the value you pass here. The default value is a string.', true)
->param('search', '', new Text(256), 'Search query. Enter any free text search. The database will try to find a match against all document attributes and children. Max length: 256 chars.', true)
->action(function ($collectionId, $filters, $limit, $offset, $orderField, $orderType, $orderCast, $search, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -526,8 +526,8 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'getDocument')
->label('sdk.description', '/docs/references/database/get-document.md')
->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, function () { return new UID(); }, 'Document unique ID.')
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->action(function ($collectionId, $documentId, $request, $response, $projectDB) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -575,11 +575,11 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'updateDocument')
->label('sdk.description', '/docs/references/database/update-document.md')
->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, function () { return new UID(); }, 'Document unique ID.')
->param('data', [], function () { return new JSON(); }, 'Document data as JSON object.')
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->param('data', [], new JSON(), 'Document data as JSON object.')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->action(function ($collectionId, $documentId, $data, $read, $write, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -624,7 +624,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
try {
$data = $projectDB->updateDocument($data);
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
throw new Exception('Unauthorized permissions', 401);
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
@@ -658,8 +658,8 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'deleteDocument')
->label('sdk.description', '/docs/references/database/delete-document.md')
->param('collectionId', null, function () { return new UID(); }, 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, function () { return new UID(); }, 'Document unique ID.')
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->action(function ($collectionId, $documentId, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -680,7 +680,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
try {
$projectDB->deleteDocument($documentId);
} catch (AuthorizationException $exception) {
throw new Exception('Unauthorized action', 401);
throw new Exception('Unauthorized permissions', 401);
} catch (StructureException $exception) {
throw new Exception('Bad structure. '.$exception->getMessage(), 400);
} catch (\Exception $exception) {
+42 -42
View File
@@ -28,12 +28,12 @@ App::post('/v1/functions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/functions/create-function.md')
->param('name', '', function () { return new Text(128); }, 'Function name.')
->param('env', '', function () { return new WhiteList(array_keys(Config::getParam('environments'))); }, 'Execution enviornment.')
->param('vars', [], function () { return new Assoc();}, 'Key-value JSON object.', true)
->param('events', [], function () { return new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)); }, 'Events list.', true)
->param('schedule', '', function () { return new Cron(); }, 'Schedule CRON syntax.', true)
->param('timeout', 15, function () { return new Range(1, 900); }, 'Function maximum execution time in seconds.', true)
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('env', '', new WhiteList(array_keys(Config::getParam('environments')), true), 'Execution enviornment.')
->param('vars', [], new Assoc(), 'Key-value JSON object.', true)
->param('events', [], new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)), 'Events list.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, 900), 'Function maximum execution time in seconds.', true)
->action(function ($name, $env, $vars, $events, $schedule, $timeout, $response, $projectDB) {
$function = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_FUNCTIONS,
@@ -73,10 +73,10 @@ App::get('/v1/functions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/functions/list-functions.md')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) {
$results = $projectDB->getCollection([
'limit' => $limit,
@@ -101,7 +101,7 @@ App::get('/v1/functions/:functionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/functions/get-function.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('functionId', '', new UID(), 'Function unique ID.')
->action(function ($functionId, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@@ -120,12 +120,12 @@ App::put('/v1/functions/:functionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/functions/update-function.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('name', '', function () { return new Text(128); }, 'Function name.')
->param('vars', [], function () { return new Assoc();}, 'Key-value JSON object.', true)
->param('events', [], function () { return new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)); }, 'Events list.', true)
->param('schedule', '', function () { return new Cron(); }, 'Schedule CRON syntax.', true)
->param('timeout', 15, function () { return new Range(1, 900); }, 'Function maximum execution time in seconds.', true)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('vars', [], new Assoc(), 'Key-value JSON object.', true)
->param('events', [], new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)), 'Events list.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, 900), 'Function maximum execution time in seconds.', true)
->action(function ($functionId, $name, $vars, $events, $schedule, $timeout, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@@ -162,8 +162,8 @@ App::patch('/v1/functions/:functionId/tag')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'updateTag')
->label('sdk.description', '/docs/references/functions/update-tag.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('tag', '', function () { return new UID(); }, 'Tag unique ID.')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tag', '', new UID(), 'Tag unique ID.')
->action(function ($functionId, $tag, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
$tag = $projectDB->getDocument($tag);
@@ -200,7 +200,7 @@ App::delete('/v1/functions/:functionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/functions/delete-function.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('functionId', '', new UID(), 'Function unique ID.')
->action(function ($functionId, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@@ -223,10 +223,10 @@ App::post('/v1/functions/:functionId/tags')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createTag')
->label('sdk.description', '/docs/references/functions/create-tag.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('command', '', function () { return new Text('1028'); }, 'Code execution command.')
->param('code', [], function () { return new File(); }, 'Gzip file containing your code.', false)
// ->param('code', '', function () { return new Text(128); }, 'Code package. Use the '.APP_NAME.' code packager to create a deployable package file.')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('command', '', new Text('1028'), 'Code execution command.')
->param('code', [], new File(), 'Gzip file containing your code.', false)
// ->param('code', '', new Text(128), 'Code package. Use the '.APP_NAME.' code packager to create a deployable package file.')
->action(function ($functionId, $command, $code, $request, $response, $projectDB, $usage) {
$function = $projectDB->getDocument($functionId);
@@ -305,11 +305,11 @@ App::get('/v1/functions/:functionId/tags')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listTags')
->label('sdk.description', '/docs/references/functions/list-tags.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($functionId, $search, $limit, $offset, $orderType, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@@ -341,8 +341,8 @@ App::get('/v1/functions/:functionId/tags/:tagId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getTag')
->label('sdk.description', '/docs/references/functions/get-tag.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('tagId', '', function () { return new UID(); }, 'Tag unique ID.')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tagId', '', new UID(), 'Tag unique ID.')
->action(function ($functionId, $tagId, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@@ -371,8 +371,8 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'deleteTag')
->label('sdk.description', '/docs/references/functions/delete-tag.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('tagId', '', function () { return new UID(); }, 'Tag unique ID.')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tagId', '', new UID(), 'Tag unique ID.')
->action(function ($functionId, $tagId, $response, $projectDB, $usage) {
$function = $projectDB->getDocument($functionId);
@@ -413,8 +413,8 @@ App::post('/v1/functions/:functionId/executions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createExecution')
->label('sdk.description', '/docs/references/functions/create-execution.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('async', 1, function () { return new Range(0, 1); }, 'Execute code asynchronously. Pass 1 for true, 0 for false. Default value is 1.', true)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('async', 1, new Range(0, 1), 'Execute code asynchronously. Pass 1 for true, 0 for false. Default value is 1.', true)
->action(function ($functionId, $async, $response, $project, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
@@ -480,11 +480,11 @@ App::get('/v1/functions/:functionId/executions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listExecutions')
->label('sdk.description', '/docs/references/functions/list-executions.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($functionId, $search, $limit, $offset, $orderType, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@@ -516,8 +516,8 @@ App::get('/v1/functions/:functionId/executions/:executionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getExecution')
->label('sdk.description', '/docs/references/functions/get-execution.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('executionId', '', function () { return new UID(); }, 'Execution unique ID.')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('executionId', '', new UID(), 'Execution unique ID.')
->action(function ($functionId, $executionId, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
+119 -227
View File
@@ -16,7 +16,6 @@ use Appwrite\Task\Validator\Cron;
use Appwrite\Database\Database;
use Appwrite\Database\Document;
use Appwrite\Database\Validator\UID;
use Appwrite\OpenSSL\OpenSSL;
use Appwrite\Network\Validator\CNAME;
use Appwrite\Network\Validator\Domain as DomainValidator;
use Cron\CronExpression;
@@ -27,17 +26,17 @@ App::post('/v1/projects')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'create')
->param('name', null, function () { return new Text(100); }, 'Project name.')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('description', '', function () { return new Text(255); }, 'Project description.', true)
->param('logo', '', function () { return new Text(1024); }, 'Project logo.', true)
->param('url', '', function () { return new URL(); }, 'Project URL.', true)
->param('legalName', '', function () { return new Text(256); }, 'Project legal Name.', true)
->param('legalCountry', '', function () { return new Text(256); }, 'Project legal Country.', true)
->param('legalState', '', function () { return new Text(256); }, 'Project legal State.', true)
->param('legalCity', '', function () { return new Text(256); }, 'Project legal City.', true)
->param('legalAddress', '', function () { return new Text(256); }, 'Project legal Address.', true)
->param('legalTaxId', '', function () { return new Text(256); }, 'Project legal Tax ID.', true)
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
->param('logo', '', new Text(1024), 'Project logo.', true)
->param('url', '', new URL(), 'Project URL.', true)
->param('legalName', '', new Text(256), 'Project legal Name. Max length: 256 chars.', true)
->param('legalCountry', '', new Text(256), 'Project legal Country. Max length: 256 chars.', true)
->param('legalState', '', new Text(256), 'Project legal State. Max length: 256 chars.', true)
->param('legalCity', '', new Text(256), 'Project legal City. Max length: 256 chars.', true)
->param('legalAddress', '', new Text(256), 'Project legal Address. Max length: 256 chars.', true)
->param('legalTaxId', '', new Text(256), 'Project legal Tax ID. Max length: 256 chars.', true)
->action(function ($name, $teamId, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId, $response, $consoleDB, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -92,10 +91,10 @@ App::get('/v1/projects')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'list')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($search, $limit, $offset, $orderType, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -111,16 +110,6 @@ App::get('/v1/projects')
'$collection='.Database::SYSTEM_COLLECTION_PROJECTS,
],
]);
foreach ($results as $project) {
foreach (Config::getParam('providers') as $provider => $node) {
$secret = \json_decode($project->getAttribute('usersOauth2'.\ucfirst($provider).'Secret', '{}'), true);
if (!empty($secret) && isset($secret['version'])) {
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$secret['version']);
$project->setAttribute('usersOauth2'.\ucfirst($provider).'Secret', OpenSSL::decrypt($secret['data'], $secret['method'], $key, 0, \hex2bin($secret['iv']), \hex2bin($secret['tag'])));
}
}
}
$response->json(['sum' => $consoleDB->getSum(), 'projects' => $results]);
}, ['response', 'consoleDB']);
@@ -131,7 +120,7 @@ App::get('/v1/projects/:projectId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'get')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -142,15 +131,6 @@ App::get('/v1/projects/:projectId')
throw new Exception('Project not found', 404);
}
foreach (Config::getParam('providers') as $provider => $node) {
$secret = \json_decode($project->getAttribute('usersOauth2'.\ucfirst($provider).'Secret', '{}'), true);
if (!empty($secret) && isset($secret['version'])) {
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$secret['version']);
$project->setAttribute('usersOauth2'.\ucfirst($provider).'Secret', OpenSSL::decrypt($secret['data'], $secret['method'], $key, 0, \hex2bin($secret['iv']), \hex2bin($secret['tag'])));
}
}
$response->json($project->getArrayCopy());
}, ['response', 'consoleDB']);
@@ -160,8 +140,8 @@ App::get('/v1/projects/:projectId/usage')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getUsage')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('range', 'last30', function () { return new WhiteList(['daily', 'monthly', 'last30', 'last90']); }, 'Date range.', true)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('range', 'last30', new WhiteList(['daily', 'monthly', 'last30', 'last90'], true), 'Date range.', true)
->action(function ($projectId, $range, $response, $consoleDB, $projectDB, $register) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -334,17 +314,17 @@ App::patch('/v1/projects/:projectId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'update')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('name', null, function () { return new Text(100); }, 'Project name.')
->param('description', '', function () { return new Text(255); }, 'Project description.', true)
->param('logo', '', function () { return new Text(1024); }, 'Project logo.', true)
->param('url', '', function () { return new URL(); }, 'Project URL.', true)
->param('legalName', '', function () { return new Text(256); }, 'Project legal name.', true)
->param('legalCountry', '', function () { return new Text(256); }, 'Project legal country..', true)
->param('legalState', '', function () { return new Text(256); }, 'Project legal state.', true)
->param('legalCity', '', function () { return new Text(256); }, 'Project legal city.', true)
->param('legalAddress', '', function () { return new Text(256); }, 'Project legal address.', true)
->param('legalTaxId', '', function () { return new Text(256); }, 'Project legal tax ID.', true)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
->param('logo', '', new Text(1024), 'Project logo.', true)
->param('url', '', new URL(), 'Project URL.', true)
->param('legalName', '', new Text(256), 'Project legal name. Max length: 256 chars.', true)
->param('legalCountry', '', new Text(256), 'Project legal country. Max length: 256 chars.', true)
->param('legalState', '', new Text(256), 'Project legal state. Max length: 256 chars.', true)
->param('legalCity', '', new Text(256), 'Project legal city. Max length: 256 chars.', true)
->param('legalAddress', '', new Text(256), 'Project legal address. Max length: 256 chars.', true)
->param('legalTaxId', '', new Text(256), 'Project legal tax ID. Max length: 256 chars.', true)
->action(function ($projectId, $name, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -381,10 +361,10 @@ App::patch('/v1/projects/:projectId/oauth2')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateOAuth2')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('provider', '', function () { return new WhiteList(\array_keys(Config::getParam('providers'))); }, 'Provider Name', false)
->param('appId', '', function () { return new Text(256); }, 'Provider app ID.', true)
->param('secret', '', function () { return new text(512); }, 'Provider secret key.', true)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'Provider Name', false)
->param('appId', '', new Text(256), 'Provider app ID. Max length: 256 chars.', true)
->param('secret', '', new text(512), 'Provider secret key. Max length: 512 chars.', true)
->action(function ($projectId, $provider, $appId, $secret, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -395,17 +375,6 @@ App::patch('/v1/projects/:projectId/oauth2')
throw new Exception('Project not found', 404);
}
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$secret = \json_encode([
'data' => OpenSSL::encrypt($secret, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => \bin2hex($iv),
'tag' => \bin2hex($tag),
'version' => '1',
]);
$project = $consoleDB->updateDocument(\array_merge($project->getArrayCopy(), [
'usersOauth2'.\ucfirst($provider).'Appid' => $appId,
'usersOauth2'.\ucfirst($provider).'Secret' => $secret,
@@ -424,8 +393,8 @@ App::delete('/v1/projects/:projectId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'delete')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('password', '', function () { return new UID(); }, 'Your user password for confirmation. Must be between 6 to 32 chars.')
->param('projectId', '', new UID(), 'Project unique ID.')
->param('password', '', new UID(), 'Your user password for confirmation. Must be between 6 to 32 chars.')
->action(function ($projectId, $password, $response, $user, $consoleDB, $deletes) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@@ -473,13 +442,13 @@ App::post('/v1/projects/:projectId/webhooks')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('name', null, function () { return new Text(256); }, 'Webhook name.')
->param('events', null, function () { return new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)); }, 'Events list.')
->param('url', null, function () { return new URL(); }, 'Webhook URL.')
->param('security', false, function () { return new Boolean(true); }, 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', function () { return new Text(256); }, 'Webhook HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Webhook HTTP password.', true)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('events', null, new ArrayList(new WhiteList(array_keys(Config::getParam('events'), true), true)), 'Events list.')
->param('url', null, new URL(), 'Webhook URL.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true)
->action(function ($projectId, $name, $events, $url, $security, $httpUser, $httpPass, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -491,16 +460,6 @@ App::post('/v1/projects/:projectId/webhooks')
}
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = \json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => \bin2hex($iv),
'tag' => \bin2hex($tag),
'version' => '1',
]);
$webhook = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_WEBHOOKS,
@@ -540,7 +499,7 @@ App::get('/v1/projects/:projectId/webhooks')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listWebhooks')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -553,18 +512,6 @@ App::get('/v1/projects/:projectId/webhooks')
$webhooks = $project->getAttribute('webhooks', []);
foreach ($webhooks as $webhook) { /* @var $webhook Document */
$httpPass = \json_decode($webhook->getAttribute('httpPass', '{}'), true);
if (empty($httpPass) || !isset($httpPass['version'])) {
continue;
}
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$webhook->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, \hex2bin($httpPass['iv']), \hex2bin($httpPass['tag'])));
}
$response->json($webhooks);
}, ['response', 'consoleDB']);
@@ -574,8 +521,8 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('webhookId', null, function () { return new UID(); }, 'Webhook unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->action(function ($projectId, $webhookId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -592,13 +539,6 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
throw new Exception('Webhook not found', 404);
}
$httpPass = \json_decode($webhook->getAttribute('httpPass', '{}'), true);
if (!empty($httpPass) && isset($httpPass['version'])) {
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$webhook->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, \hex2bin($httpPass['iv']), \hex2bin($httpPass['tag'])));
}
$response->json($webhook->getArrayCopy());
}, ['response', 'consoleDB']);
@@ -608,13 +548,14 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('webhookId', null, function () { return new UID(); }, 'Webhook unique ID.')
->param('name', null, function () { return new Text(256); }, 'Webhook name.')
->param('events', null, function () { return new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)); }, 'Events list.')
->param('url', null, function () { return new URL(); }, 'Webhook URL.')
->param('security', false, function () { return new Boolean(true); }, 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', function () { return new Text(256); }, 'Webhook HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Webhook HTTP password.', true)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('events', null, new ArrayList(new WhiteList(array_keys(Config::getParam('events'), true), true)), 'Events list.')
->param('url', null, new URL(), 'Webhook URL.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true)
->action(function ($projectId, $webhookId, $name, $events, $url, $security, $httpUser, $httpPass, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -626,16 +567,6 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
}
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = \json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => \bin2hex($iv),
'tag' => \bin2hex($tag),
'version' => '1',
]);
$webhook = $project->search('$id', $webhookId, $project->getAttribute('webhooks', []));
@@ -665,8 +596,8 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('webhookId', null, function () { return new UID(); }, 'Webhook unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->action(function ($projectId, $webhookId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -698,9 +629,9 @@ App::post('/v1/projects/:projectId/keys')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('name', null, function () { return new Text(256); }, 'Key name.')
->param('scopes', null, function () { return new ArrayList(new WhiteList(Config::getParam('scopes'))); }, 'Key scopes list.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
->param('scopes', null, new ArrayList(new WhiteList(Config::getParam('scopes'), true)), 'Key scopes list.')
->action(function ($projectId, $name, $scopes, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -746,7 +677,7 @@ App::get('/v1/projects/:projectId/keys')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listKeys')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -766,8 +697,8 @@ App::get('/v1/projects/:projectId/keys/:keyId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('keyId', null, function () { return new UID(); }, 'Key unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('keyId', null, new UID(), 'Key unique ID.')
->action(function ($projectId, $keyId, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
@@ -790,10 +721,10 @@ App::put('/v1/projects/:projectId/keys/:keyId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('keyId', null, function () { return new UID(); }, 'Key unique ID.')
->param('name', null, function () { return new Text(256); }, 'Key name.')
->param('scopes', null, function () { return new ArrayList(new WhiteList(Config::getParam('scopes'))); }, 'Key scopes list')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('keyId', null, new UID(), 'Key unique ID.')
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
->param('scopes', null, new ArrayList(new WhiteList(Config::getParam('scopes'), true)), 'Key scopes list')
->action(function ($projectId, $keyId, $name, $scopes, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -828,8 +759,8 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('keyId', null, function () { return new UID(); }, 'Key unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('keyId', null, new UID(), 'Key unique ID.')
->action(function ($projectId, $keyId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -861,16 +792,16 @@ App::post('/v1/projects/:projectId/tasks')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('name', null, function () { return new Text(256); }, 'Task name.')
->param('status', null, function () { return new WhiteList(['play', 'pause']); }, 'Task status.')
->param('schedule', null, function () { return new Cron(); }, 'Task schedule CRON syntax.')
->param('security', false, function () { return new Boolean(true); }, 'Certificate verification, false for disabled or true for enabled.')
->param('httpMethod', '', function () { return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']); }, 'Task HTTP method.')
->param('httpUrl', '', function () { return new URL(); }, 'Task HTTP URL')
->param('httpHeaders', null, function () { return new ArrayList(new Text(256)); }, 'Task HTTP headers list.', true)
->param('httpUser', '', function () { return new Text(256); }, 'Task HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Task HTTP password.', true)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Task name. Max length: 128 chars.')
->param('status', null, new WhiteList(['play', 'pause'], true), 'Task status.')
->param('schedule', null, new Cron(), 'Task schedule CRON syntax.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpMethod', '', new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], true), 'Task HTTP method.')
->param('httpUrl', '', new URL(), 'Task HTTP URL')
->param('httpHeaders', null, new ArrayList(new Text(256)), 'Task HTTP headers list.', true)
->param('httpUser', '', new Text(256), 'Task HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Task HTTP password. Max length: 256 chars.', true)
->action(function ($projectId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -885,16 +816,6 @@ App::post('/v1/projects/:projectId/tasks')
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = \json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => \bin2hex($iv),
'tag' => \bin2hex($tag),
'version' => '1',
]);
$task = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_TASKS,
@@ -946,7 +867,7 @@ App::get('/v1/projects/:projectId/tasks')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listTasks')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -959,18 +880,6 @@ App::get('/v1/projects/:projectId/tasks')
$tasks = $project->getAttribute('tasks', []);
foreach ($tasks as $task) { /* @var $task Document */
$httpPass = \json_decode($task->getAttribute('httpPass', '{}'), true);
if (empty($httpPass) || !isset($httpPass['version'])) {
continue;
}
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$task->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, \hex2bin($httpPass['iv']), \hex2bin($httpPass['tag'])));
}
$response->json($tasks);
}, ['response', 'consoleDB']);
@@ -980,8 +889,8 @@ App::get('/v1/projects/:projectId/tasks/:taskId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('taskId', null, function () { return new UID(); }, 'Task unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->action(function ($projectId, $taskId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -998,13 +907,6 @@ App::get('/v1/projects/:projectId/tasks/:taskId')
throw new Exception('Task not found', 404);
}
$httpPass = \json_decode($task->getAttribute('httpPass', '{}'), true);
if (!empty($httpPass) && isset($httpPass['version'])) {
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$task->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, \hex2bin($httpPass['iv']), \hex2bin($httpPass['tag'])));
}
$response->json($task->getArrayCopy());
}, ['response', 'consoleDB']);
@@ -1014,17 +916,17 @@ App::put('/v1/projects/:projectId/tasks/:taskId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('taskId', null, function () { return new UID(); }, 'Task unique ID.')
->param('name', null, function () { return new Text(256); }, 'Task name.')
->param('status', null, function () { return new WhiteList(['play', 'pause']); }, 'Task status.')
->param('schedule', null, function () { return new Cron(); }, 'Task schedule CRON syntax.')
->param('security', false, function () { return new Boolean(true); }, 'Certificate verification, false for disabled or true for enabled.')
->param('httpMethod', '', function () { return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']); }, 'Task HTTP method.')
->param('httpUrl', '', function () { return new URL(); }, 'Task HTTP URL.')
->param('httpHeaders', null, function () { return new ArrayList(new Text(256)); }, 'Task HTTP headers list.', true)
->param('httpUser', '', function () { return new Text(256); }, 'Task HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Task HTTP password.', true)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->param('name', null, new Text(128), 'Task name. Max length: 128 chars.')
->param('status', null, new WhiteList(['play', 'pause'], true), 'Task status.')
->param('schedule', null, new Cron(), 'Task schedule CRON syntax.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpMethod', '', new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], true), 'Task HTTP method.')
->param('httpUrl', '', new URL(), 'Task HTTP URL.')
->param('httpHeaders', null, new ArrayList(new Text(256)), 'Task HTTP headers list.', true)
->param('httpUser', '', new Text(256), 'Task HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Task HTTP password. Max length: 256 chars.', true)
->action(function ($projectId, $taskId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1045,16 +947,6 @@ App::put('/v1/projects/:projectId/tasks/:taskId')
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = \json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => \bin2hex($iv),
'tag' => \bin2hex($tag),
'version' => '1',
]);
$task
->setAttribute('name', $name)
@@ -1087,8 +979,8 @@ App::delete('/v1/projects/:projectId/tasks/:taskId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('taskId', null, function () { return new UID(); }, 'Task unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->action(function ($projectId, $taskId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1120,12 +1012,12 @@ App::post('/v1/projects/:projectId/platforms')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createPlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('type', null, function () { return new WhiteList(['web', 'flutter-ios', 'flutter-android', 'ios', 'android', 'unity']); }, 'Platform type.')
->param('name', null, function () { return new Text(256); }, 'Platform name.')
->param('key', '', function () { return new Text(256); }, 'Package name for android or bundle ID for iOS.', true)
->param('store', '', function () { return new Text(256); }, 'App store or Google Play store ID.', true)
->param('hostname', '', function () { return new Text(256); }, 'Platform client hostname.', true)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('type', null, new WhiteList(['web', 'flutter-ios', 'flutter-android', 'ios', 'android', '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. Max length: 256 chars.', true)
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
->param('hostname', '', new Text(256), 'Platform client hostname. Max length: 256 chars.', true)
->action(function ($projectId, $type, $name, $key, $store, $hostname, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1175,7 +1067,7 @@ App::get('/v1/projects/:projectId/platforms')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listPlatforms')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1197,8 +1089,8 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getPlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('platformId', null, function () { return new UID(); }, 'Platform unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('platformId', null, new UID(), 'Platform unique ID.')
->action(function ($projectId, $platformId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1224,12 +1116,12 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updatePlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('platformId', null, function () { return new UID(); }, 'Platform unique ID.')
->param('name', null, function () { return new Text(256); }, 'Platform name.')
->param('key', '', function () { return new Text(256); }, 'Package name for android or bundle ID for iOS.', true)
->param('store', '', function () { return new Text(256); }, 'App store or Google Play store ID.', true)
->param('hostname', '', function () { return new Text(256); }, 'Platform client URL.', true)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('platformId', null, 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)
->param('hostname', '', new Text(256), 'Platform client URL. Max length: 256 chars.', true)
->action(function ($projectId, $platformId, $name, $key, $store, $hostname, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1267,8 +1159,8 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deletePlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('platformId', null, function () { return new UID(); }, 'Platform unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('platformId', null, new UID(), 'Platform unique ID.')
->action(function ($projectId, $platformId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1300,8 +1192,8 @@ App::post('/v1/projects/:projectId/domains')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createDomain')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domain', null, function () { return new DomainValidator(); }, 'Domain name.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domain', null, new DomainValidator(), 'Domain name.')
->action(function ($projectId, $domain, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1364,7 +1256,7 @@ App::get('/v1/projects/:projectId/domains')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listDomains')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1386,8 +1278,8 @@ App::get('/v1/projects/:projectId/domains/:domainId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getDomain')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domainId', null, function () { return new UID(); }, 'Domain unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domainId', null, new UID(), 'Domain unique ID.')
->action(function ($projectId, $domainId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1413,8 +1305,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateDomainVerification')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domainId', null, function () { return new UID(); }, 'Domain unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domainId', null, new UID(), 'Domain unique ID.')
->action(function ($projectId, $domainId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
@@ -1471,8 +1363,8 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteDomain')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domainId', null, function () { return new UID(); }, 'Domain unique ID.')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domainId', null, new UID(), 'Domain unique ID.')
->action(function ($projectId, $domainId, $response, $consoleDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
+23 -23
View File
@@ -33,9 +33,9 @@ App::post('/v1/storage/files')
->label('sdk.description', '/docs/references/storage/create-file.md')
->label('sdk.consumes', 'multipart/form-data')
->label('sdk.methodType', 'upload')
->param('file', [], function () { return new File(); }, 'Binary file.', false)
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('file', [], new File(), 'Binary file.', false)
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->action(function ($file, $read, $write, $request, $response, $user, $projectDB, $webhooks, $audits, $usage) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -167,10 +167,10 @@ App::get('/v1/storage/files')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'listFiles')
->label('sdk.description', '/docs/references/storage/list-files.md')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -202,7 +202,7 @@ App::get('/v1/storage/files/:fileId')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFile')
->label('sdk.description', '/docs/references/storage/get-file.md')
->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
->param('fileId', '', new UID(), 'File unique ID.')
->action(function ($fileId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -226,12 +226,12 @@ App::get('/v1/storage/files/:fileId/preview')
->label('sdk.description', '/docs/references/storage/get-file-preview.md')
->label('sdk.response.type', 'image/*')
->label('sdk.methodType', 'location')
->param('fileId', '', function () { return new UID(); }, 'File unique ID')
->param('width', 0, function () { return new Range(0, 4000); }, 'Resize preview image width, Pass an integer between 0 to 4000.', true)
->param('height', 0, function () { return new Range(0, 4000); }, 'Resize preview image height, Pass an integer between 0 to 4000.', true)
->param('quality', 100, function () { return new Range(0, 100); }, 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('background', '', function () { return new HexColor(); }, 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true)
->param('output', '', function () { return new WhiteList(\array_keys(Config::getParam('storage-outputs'))); }, 'Output format type (jpeg, jpg, png, gif and webp).', true)
->param('fileId', '', new UID(), 'File unique ID')
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('background', '', new HexColor(), 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true)
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
->action(function ($fileId, $width, $height, $quality, $background, $output, $request, $response, $project, $projectDB) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -352,7 +352,7 @@ App::get('/v1/storage/files/:fileId/download')
->label('sdk.description', '/docs/references/storage/get-file-download.md')
->label('sdk.response.type', '*')
->label('sdk.methodType', 'location')
->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
->param('fileId', '', new UID(), 'File unique ID.')
->action(function ($fileId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -407,8 +407,8 @@ App::get('/v1/storage/files/:fileId/view')
->label('sdk.description', '/docs/references/storage/get-file-view.md')
->label('sdk.response.type', '*')
->label('sdk.methodType', 'location')
->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
->param('as', '', function () { return new WhiteList(['pdf', /*'html',*/ 'text']); }, 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true)
->param('fileId', '', new UID(), 'File unique ID.')
->param('as', '', new WhiteList(['pdf', /*'html',*/ 'text'], true), 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true)
->action(function ($fileId, $as, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -479,9 +479,9 @@ App::put('/v1/storage/files/:fileId')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'updateFile')
->label('sdk.description', '/docs/references/storage/update-file.md')
->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('fileId', '', new UID(), 'File unique ID.')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->action(function ($fileId, $read, $write, $response, $projectDB, $webhooks, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -527,7 +527,7 @@ App::delete('/v1/storage/files/:fileId')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'deleteFile')
->label('sdk.description', '/docs/references/storage/delete-file.md')
->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
->param('fileId', '', new UID(), 'File unique ID.')
->action(function ($fileId, $response, $projectDB, $webhooks, $audits, $usage) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -573,8 +573,8 @@ App::delete('/v1/storage/files/:fileId')
// ->label('sdk.namespace', 'storage')
// ->label('sdk.method', 'getFileScan')
// ->label('sdk.hide', true)
// ->param('fileId', '', function () { return new UID(); }, 'File unique ID.')
// ->param('storage', 'files', function () { return new WhiteList(['files']);})
// ->param('fileId', '', new UID(), 'File unique ID.')
// ->param('storage', 'files', new WhiteList(['files']);})
// ->action(
// function ($fileId, $storage) use ($response, $request, $projectDB) {
// $file = $projectDB->getDocument($fileId);
+26 -25
View File
@@ -15,6 +15,7 @@ use Appwrite\Database\Document;
use Appwrite\Database\Validator\UID;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Database\Exception\Duplicate;
use Appwrite\Database\Validator\Key;
use Appwrite\Template\Template;
use Appwrite\Utopia\Response;
@@ -26,8 +27,8 @@ App::post('/v1/teams')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/teams/create-team.md')
->param('name', null, function () { return new Text(100); }, 'Team name.')
->param('roles', ['owner'], function () { return new ArrayList(new Text(128)); }, 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions).', true)
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
->param('roles', ['owner'], new ArrayList(new Key()), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.', true)
->action(function ($name, $roles, $response, $user, $projectDB, $mode) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@@ -93,10 +94,10 @@ App::get('/v1/teams')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/teams/list-teams.md')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -124,7 +125,7 @@ App::get('/v1/teams/:teamId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/teams/get-team.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('teamId', '', new UID(), 'Team unique ID.')
->action(function ($teamId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -146,8 +147,8 @@ App::put('/v1/teams/:teamId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/teams/update-team.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('name', null, function () { return new Text(100); }, 'Team name.')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
->action(function ($teamId, $name, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -177,7 +178,7 @@ App::delete('/v1/teams/:teamId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/teams/delete-team.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('teamId', '', new UID(), 'Team unique ID.')
->action(function ($teamId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -218,10 +219,10 @@ App::post('/v1/teams/:teamId/memberships')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'createMembership')
->label('sdk.description', '/docs/references/teams/create-team-membership.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('email', '', function () { return new Email(); }, 'New team member email.')
->param('name', '', function () { return new Text(100); }, 'New team member name.', true)
->param('roles', [], function () { return new ArrayList(new Text(128)); }, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions).')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('email', '', new Email(), 'New team member email.')
->param('name', '', new Text(128), 'New team member name. Max length: 128 chars.', true)
->param('roles', [], new ArrayList(new Key()), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.')
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
->action(function ($teamId, $email, $name, $roles, $url, $response, $project, $user, $projectDB, $locale, $audits, $mails, $mode) {
/** @var Utopia\Response $response */
@@ -415,11 +416,11 @@ App::get('/v1/teams/:teamId/memberships')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'getMemberships')
->label('sdk.description', '/docs/references/teams/get-team-members.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('teamId', '', new UID(), 'Team unique ID.')
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($teamId, $search, $limit, $offset, $orderType, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -474,10 +475,10 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updateMembershipStatus')
->label('sdk.description', '/docs/references/teams/update-team-membership-status.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('inviteId', '', function () { return new UID(); }, 'Invite unique ID.')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('secret', '', function () { return new Text(256); }, 'Secret key.')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('inviteId', '', new UID(), 'Invite unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
->param('secret', '', new Text(256), 'Secret key.')
->action(function ($teamId, $inviteId, $userId, $secret, $request, $response, $user, $projectDB, $audits) {
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
@@ -604,8 +605,8 @@ App::delete('/v1/teams/:teamId/memberships/:inviteId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'deleteMembership')
->label('sdk.description', '/docs/references/teams/delete-team-membership.md')
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
->param('inviteId', '', function () { return new UID(); }, 'Invite unique ID.')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('inviteId', '', new UID(), 'Invite unique ID.')
->action(function ($teamId, $inviteId, $response, $projectDB, $audits) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
+63 -18
View File
@@ -26,9 +26,9 @@ App::post('/v1/users')
->label('sdk.namespace', 'users')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/users/create-user.md')
->param('email', '', function () { return new Email(); }, 'User email.')
->param('password', '', function () { return new Password(); }, 'User password. Must be between 6 to 32 chars.')
->param('name', '', function () { return new Text(100); }, 'User name.', true)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->action(function ($email, $password, $name, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -96,10 +96,10 @@ App::get('/v1/users')
->label('sdk.namespace', 'users')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/users/list-users.md')
->param('search', '', function () { return new Text(256); }, 'Search term to filter your list results.', true)
->param('limit', 25, function () { return new Range(0, 100); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, function () { return new Range(0, 2000); }, 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', function () { return new WhiteList(['ASC', 'DESC']); }, 'Order result by ASC or DESC order.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -152,7 +152,7 @@ App::get('/v1/users/:userId')
->label('sdk.namespace', 'users')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/users/get-user.md')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -195,7 +195,7 @@ App::get('/v1/users/:userId/prefs')
->label('sdk.namespace', 'users')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/users/get-user-prefs.md')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -226,7 +226,7 @@ App::get('/v1/users/:userId/sessions')
->label('sdk.namespace', 'users')
->label('sdk.method', 'getSessions')
->label('sdk.description', '/docs/references/users/get-user-sessions.md')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB, $locale, $geodb) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -292,7 +292,7 @@ App::get('/v1/users/:userId/logs')
->label('sdk.namespace', 'users')
->label('sdk.method', 'getLogs')
->label('sdk.description', '/docs/references/users/get-user-logs.md')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $register, $project, $projectDB, $locale, $geodb) {
/** @var Utopia\Response $response */
/** @var Utopia\Registry\Registry $register */
@@ -377,8 +377,8 @@ App::patch('/v1/users/:userId/status')
->label('sdk.namespace', 'users')
->label('sdk.method', 'updateStatus')
->label('sdk.description', '/docs/references/users/update-user-status.md')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('status', '', function () { return new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED]); }, 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to block the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED)
->param('userId', '', new UID(), 'User unique ID.')
->param('status', '', new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED], true), 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to block the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED)
->action(function ($userId, $status, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -427,8 +427,8 @@ App::patch('/v1/users/:userId/prefs')
->label('sdk.namespace', 'users')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/users/update-user-prefs.md')
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('prefs', '', function () { return new Assoc();}, 'Prefs key-value JSON object.')
->param('userId', '', new UID(), 'User unique ID.')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->action(function ($userId, $prefs, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -471,8 +471,8 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
->label('sdk.method', 'deleteSession')
->label('sdk.description', '/docs/references/users/delete-user-session.md')
->label('abuse-limit', 100)
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('sessionId', null, function () { return new UID(); }, 'User unique session ID.')
->param('userId', '', new UID(), 'User unique ID.')
->param('sessionId', null, new UID(), 'User unique session ID.')
->action(function ($userId, $sessionId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -505,7 +505,7 @@ App::delete('/v1/users/:userId/sessions')
->label('sdk.method', 'deleteSessions')
->label('sdk.description', '/docs/references/users/delete-user-sessions.md')
->label('abuse-limit', 100)
->param('userId', '', function () { return new UID(); }, 'User unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -526,3 +526,48 @@ App::delete('/v1/users/:userId/sessions')
$response->json(array('result' => 'success'));
}, ['response', 'projectDB']);
App::delete('/v1/users/:userId')
->desc('Delete User')
->groups(['api', 'users'])
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteUser')
->label('sdk.description', '/docs/references/users/delete-user.md')
->label('abuse-limit', 100)
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(function ($userId, $response, $projectDB, $deletes) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Appwrite\Event\Event $deletes */
$user = $projectDB->getDocument($userId);
if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) {
throw new Exception('User not found', 404);
}
if (!$projectDB->deleteDocument($userId)) {
throw new Exception('Failed to remove user from DB', 500);
}
if (!$projectDB->deleteUniqueKey(md5('users:email='.$user->getAttribute('email', null)))) {
throw new Exception('Failed to remove unique key from DB', 500);
}
$reservedId = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_RESERVED,
'$id' => $userId,
'$permissions' => [
'read' => ['*'],
],
]);
if (false === $reservedId) {
throw new Exception('Failed saving reserved id to DB', 500);
}
$deletes->setParam('document', $user);
$response->noContent();
}, ['response', 'projectDB', 'deletes']);
+1 -1
View File
@@ -301,7 +301,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
/** @var Exception $error */
/** @var Utopia\App $utopia */
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\View $layout */
/** @var Appwrite\Database\Document $project */
+76 -55
View File
@@ -12,148 +12,159 @@ use Appwrite\Storage\Validator\File;
App::get('/v1/mock/tests/foo')
->desc('Mock a get request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'foo')
->label('sdk.method', 'get')
->label('sdk.description', 'Mock a get request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::post('/v1/mock/tests/foo')
->desc('Mock a post request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'foo')
->label('sdk.method', 'post')
->label('sdk.description', 'Mock a post request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::patch('/v1/mock/tests/foo')
->desc('Mock a patch request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'foo')
->label('sdk.method', 'patch')
->label('sdk.description', 'Mock a get request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::put('/v1/mock/tests/foo')
->desc('Mock a put request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'foo')
->label('sdk.method', 'put')
->label('sdk.description', 'Mock a put request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::delete('/v1/mock/tests/foo')
->desc('Mock a delete request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'foo')
->label('sdk.method', 'delete')
->label('sdk.description', 'Mock a delete request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::get('/v1/mock/tests/bar')
->desc('Mock a get request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'bar')
->label('sdk.method', 'get')
->label('sdk.description', 'Mock a get request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::post('/v1/mock/tests/bar')
->desc('Mock a post request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'bar')
->label('sdk.method', 'post')
->label('sdk.description', 'Mock a post request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::patch('/v1/mock/tests/bar')
->desc('Mock a patch request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'bar')
->label('sdk.method', 'patch')
->label('sdk.description', 'Mock a get request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::put('/v1/mock/tests/bar')
->desc('Mock a put request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'bar')
->label('sdk.method', 'put')
->label('sdk.description', 'Mock a put request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::delete('/v1/mock/tests/bar')
->desc('Mock a delete request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'bar')
->label('sdk.method', 'delete')
->label('sdk.description', 'Mock a delete request for SDK tests')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->action(function ($x, $y, $z) {
});
App::post('/v1/mock/tests/general/upload')
->desc('Mock a post request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'general')
->label('sdk.method', 'upload')
->label('sdk.description', 'Mock a delete request for SDK tests')
->label('sdk.consumes', 'multipart/form-data')
->label('sdk.mock', true)
->param('x', '', function () { return new Text(100); }, 'Sample string param')
->param('y', '', function () { return new Numeric(); }, 'Sample numeric param')
->param('z', null, function () { return new ArrayList(new Text(256)); }, 'Sample array param')
->param('file', [], function () { return new File(); }, 'Sample file param', false)
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256)), 'Sample array param')
->param('file', [], new File(), 'Sample file param', false)
->action(function ($x, $y, $z, $file, $request) {
/** @var Utopia\Request $request */
/** @var Utopia\Swoole\Request $request */
$file = $request->getFiles('file');
$file['tmp_name'] = (\is_array($file['tmp_name'])) ? $file['tmp_name'] : [$file['tmp_name']];
@@ -181,19 +192,21 @@ App::post('/v1/mock/tests/general/upload')
App::get('/v1/mock/tests/general/redirect')
->desc('Mock a post request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'general')
->label('sdk.method', 'redirect')
->label('sdk.description', 'Mock a redirect request for SDK tests')
->label('sdk.mock', true)
->action(function ($response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
$response->redirect('/v1/mock/tests/general/redirected');
}, ['response']);
App::get('/v1/mock/tests/general/redirected')
->desc('Mock a post request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'general')
->label('sdk.method', 'redirected')
@@ -204,26 +217,28 @@ App::get('/v1/mock/tests/general/redirected')
App::get('/v1/mock/tests/general/set-cookie')
->desc('Mock a cookie request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'general')
->label('sdk.method', 'setCookie')
->label('sdk.description', 'Mock a set cookie request for SDK tests')
->label('sdk.mock', true)
->action(function ($response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
$response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', 'localhost', true, true);
}, ['response']);
App::get('/v1/mock/tests/general/get-cookie')
->desc('Mock a cookie request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'general')
->label('sdk.method', 'getCookie')
->label('sdk.description', 'Mock a get cookie request for SDK tests')
->label('sdk.mock', true)
->action(function ($request) {
/** @var Utopia\Request $request */
/** @var Utopia\Swoole\Request $request */
if ($request->getCookie('cookieName', '') !== 'cookieValue') {
throw new Exception('Missing cookie value', 400);
@@ -232,13 +247,14 @@ App::get('/v1/mock/tests/general/get-cookie')
App::get('/v1/mock/tests/general/empty')
->desc('Mock a post request for SDK tests')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.namespace', 'general')
->label('sdk.method', 'empty')
->label('sdk.description', 'Mock a redirected request for SDK tests')
->label('sdk.mock', true)
->action(function ($response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
$response->noContent();
exit();
@@ -246,30 +262,32 @@ App::get('/v1/mock/tests/general/empty')
App::get('/v1/mock/tests/general/oauth2')
->desc('Mock an OAuth2 login route')
->groups(['mock'])
->label('scope', 'public')
->label('docs', false)
->label('sdk.mock', true)
->param('client_id', '', function () { return new Text(100); }, 'OAuth2 Client ID.')
->param('redirect_uri', '', function () { return new Host(['localhost']); }, 'OAuth2 Redirect URI.') // Important to deny an open redirect attack
->param('scope', '', function () { return new Text(100); }, 'OAuth2 scope list.')
->param('state', '', function () { return new Text(1024); }, 'OAuth2 state.')
->param('client_id', '', new Text(100), 'OAuth2 Client ID.')
->param('redirect_uri', '', new Host(['localhost']), 'OAuth2 Redirect URI.') // Important to deny an open redirect attack
->param('scope', '', new Text(100), 'OAuth2 scope list.')
->param('state', '', new Text(1024), 'OAuth2 state.')
->action(function ($clientId, $redirectURI, $scope, $state, $response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
$response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state]));
}, ['response']);
App::get('/v1/mock/tests/general/oauth2/token')
->desc('Mock an OAuth2 login route')
->groups(['mock'])
->label('scope', 'public')
->label('docs', false)
->label('sdk.mock', true)
->param('client_id', '', function () { return new Text(100); }, 'OAuth2 Client ID.')
->param('redirect_uri', '', function () { return new Host(['localhost']); }, 'OAuth2 Redirect URI.')
->param('client_secret', '', function () { return new Text(100); }, 'OAuth2 scope list.')
->param('code', '', function () { return new Text(100); }, 'OAuth2 state.')
->param('client_id', '', new Text(100), 'OAuth2 Client ID.')
->param('redirect_uri', '', new Host(['localhost']), 'OAuth2 Redirect URI.')
->param('client_secret', '', new Text(100), 'OAuth2 scope list.')
->param('code', '', new Text(100), 'OAuth2 state.')
->action(function ($clientId, $redirectURI, $clientSecret, $code, $response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
if ($clientId != '1') {
throw new Exception('Invalid client ID');
@@ -288,11 +306,12 @@ App::get('/v1/mock/tests/general/oauth2/token')
App::get('/v1/mock/tests/general/oauth2/user')
->desc('Mock an OAuth2 user route')
->groups(['mock'])
->label('scope', 'public')
->label('docs', false)
->param('token', '', function () { return new Text(100); }, 'OAuth2 Access Token.')
->param('token', '', new Text(100), 'OAuth2 Access Token.')
->action(function ($token, $response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
if ($token != '123456') {
throw new Exception('Invalid token');
@@ -307,9 +326,10 @@ App::get('/v1/mock/tests/general/oauth2/user')
App::get('/v1/mock/tests/general/oauth2/success')
->label('scope', 'public')
->groups(['mock'])
->label('docs', false)
->action(function ($response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
$response->json([
'result' => 'success',
@@ -317,10 +337,11 @@ App::get('/v1/mock/tests/general/oauth2/success')
}, ['response']);
App::get('/v1/mock/tests/general/oauth2/failure')
->groups(['mock'])
->label('scope', 'public')
->label('docs', false)
->action(function ($response) {
/** @var Utopia\Response $response */
/** @var Appwrite\Utopia\Response $response */
$response
->setStatusCode(Response::STATUS_CODE_BAD_REQUEST)
@@ -331,8 +352,8 @@ App::get('/v1/mock/tests/general/oauth2/failure')
App::shutdown(function($utopia, $response, $request) {
/** @var Utopia\App $utopia */
/** @var Utopia\Request $request */
/** @var Utopia\Response $response */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
$result = [];
$route = $utopia->match($request);
+3 -1
View File
@@ -36,7 +36,9 @@ App::init(function ($utopia, $request, $response, $layout) {
$response
->addHeader('Cache-Control', 'public, max-age='.$time)
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time).' GMT') // 45 days cache
->addHeader('X-UA-Compatible', 'IE=Edge'); // Deny IE browsers from going into quirks mode
->addHeader('X-Frame-Options', 'SAMEORIGIN') // Avoid console and homepage from showing in iframes
->addHeader('X-UA-Compatible', 'IE=Edge') // Deny IE browsers from going into quirks mode
;
$route = $utopia->match($request);
$scope = $route->getLabel('scope', '');
+2 -2
View File
@@ -211,7 +211,7 @@ App::get('/console/database/collection')
->groups(['web', 'console'])
->label('permission', 'public')
->label('scope', 'console')
->param('id', '', function () { return new UID(); }, 'Collection unique ID.')
->param('id', '', new UID(), 'Collection unique ID.')
->action(function ($id, $response, $layout, $projectDB) {
/** @var Utopia\Response $response */
/** @var Utopia\View $layout */
@@ -247,7 +247,7 @@ App::get('/console/database/document')
->groups(['web', 'console'])
->label('permission', 'public')
->label('scope', 'console')
->param('collection', '', function () { return new UID(); }, 'Collection unique ID.')
->param('collection', '', new UID(), 'Collection unique ID.')
->action(function ($collection, $layout, $projectDB) {
/** @var Utopia\View $layout */
/** @var Appwrite\Database\Database $projectDB */
+3 -3
View File
@@ -184,9 +184,9 @@ App::get('/open-api-2.json')
->groups(['web', 'home'])
->label('scope', 'public')
->label('docs', false)
->param('platform', APP_PLATFORM_CLIENT, function () {return new WhiteList([APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER, APP_PLATFORM_CONSOLE]);}, 'Choose target platform.', true)
->param('extensions', 0, function () {return new Range(0, 1);}, 'Show extra data.', true)
->param('tests', 0, function () {return new Range(0, 1);}, 'Include only test services.', true)
->param('platform', APP_PLATFORM_CLIENT, new WhiteList([APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER, APP_PLATFORM_CONSOLE], true), 'Choose target platform.', true)
->param('extensions', 0, new Range(0, 1), 'Show extra data.', true)
->param('tests', 0, new Range(0, 1), 'Include only test services.', true)
->action(function ($platform, $extensions, $tests, $utopia, $request, $response) {
/** @var Utopia\App $utopia */
/** @var Utopia\Request $request */
+1
View File
@@ -454,5 +454,6 @@ App::setResource('mode', function($request) {
}, ['request']);
App::setResource('geodb', function($request) {
/** @var Utopia\Request $request */
return new Reader(__DIR__.'/db/DBIP/dbip-country-lite-2020-01.mmdb');
}, ['request']);
+13
View File
@@ -1,3 +1,16 @@
## 0.3.2
- Fixed package namespaces
## 0.3.1
- Downgraded meta package version to 1.1.8
## 0.3.0
- Updated package dependencies (@lohanidamodar)
- Added Flutter for Web compatibility (@lohanidamodar)
## 0.2.3
- Fixed OAuth2 cookie bug, where a new session cookie couldn&#039;t overwrite an old cookie
+2 -2
View File
@@ -20,13 +20,13 @@ Add this to your package's `pubspec.yaml` file:
```yml
dependencies:
appwrite: ^0.2.3
appwrite_dev: ^0.3.2
```
You can install packages from the command line:
```bash
pub get appwrite
pub get appwrite_dev
```
## Contribution
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,5 +1,5 @@
import 'dart:io';
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -1,4 +1,4 @@
import 'package:appwrite/appwrite.dart';
import 'package:appwrite_dev/appwrite_dev.dart';
void main() { // Init SDK
Client client = Client();
@@ -0,0 +1,10 @@
export 'package:dio/dio.dart' show Response;
export 'client.dart';
export 'enums.dart';
export 'services/account.dart';
export 'services/avatars.dart';
export 'services/database.dart';
export 'services/locale.dart';
export 'services/storage.dart';
export 'services/teams.dart';
+28 -16
View File
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:dio/adapter.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:cookie_jar/cookie_jar.dart';
@@ -20,17 +21,21 @@ class Client {
PersistCookieJar cookieJar;
Client({this.endPoint = 'https://appwrite.io/v1', this.selfSigned = false, Dio http}) : this.http = http ?? Dio() {
type = (Platform.isIOS) ? 'ios' : type;
type = (Platform.isMacOS) ? 'macos' : type;
type = (Platform.isAndroid) ? 'android' : type;
type = (Platform.isLinux) ? 'linux' : type;
type = (Platform.isWindows) ? 'windows' : type;
type = (Platform.isFuchsia) ? 'fuchsia' : type;
// Platform is not supported in web so if web, set type to web automatically and skip Platform check
if(kIsWeb) {
type = 'web';
}else{
type = (Platform.isIOS) ? 'ios' : type;
type = (Platform.isMacOS) ? 'macos' : type;
type = (Platform.isAndroid) ? 'android' : type;
type = (Platform.isLinux) ? 'linux' : type;
type = (Platform.isWindows) ? 'windows' : type;
type = (Platform.isFuchsia) ? 'fuchsia' : type;
}
this.headers = {
'content-type': 'application/json',
'x-sdk-version': 'appwrite:dart:0.2.3',
'x-sdk-version': 'appwrite:flutter:0.3.2',
};
this.config = {};
@@ -78,17 +83,20 @@ class Client {
Future init() async {
if(!initialized) {
final Directory cookieDir = await _getCookiePath();
cookieJar = new PersistCookieJar(dir:cookieDir.path);
// if web skip cookie implementation and origin header as those are automatically handled by browsers
if(!kIsWeb) {
final Directory cookieDir = await _getCookiePath();
cookieJar = new PersistCookieJar(dir:cookieDir.path);
this.http.interceptors.add(CookieManager(cookieJar));
PackageInfo packageInfo = await PackageInfo.fromPlatform();
addHeader('Origin', 'appwrite-' + type + '://' + packageInfo.packageName);
}else{
// if web set httpClientAdapter as BrowserHttpClientAdapter with withCredentials true to make cookies work
this.http.options.extra['withCredentials'] = true;
}
this.http.options.baseUrl = this.endPoint;
this.http.options.validateStatus = (status) => status < 400;
this.http.interceptors.add(CookieManager(cookieJar));
PackageInfo packageInfo = await PackageInfo.fromPlatform();
addHeader('Origin', 'appwrite-' + type + '://' + packageInfo.packageName);
}
}
@@ -114,6 +122,10 @@ class Client {
}
if (method == HttpMethod.get) {
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
return http.get(path, queryParameters: params, options: options);
} else {
return http.request(path, data: params, options: options);
@@ -27,6 +27,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -55,6 +59,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -79,6 +87,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -106,6 +118,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -134,6 +150,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -161,6 +181,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -124,6 +124,10 @@ class Storage extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -154,6 +158,10 @@ class Storage extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -178,6 +186,10 @@ class Storage extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
+7 -22
View File
@@ -1,5 +1,5 @@
name: appwrite
version: 0.2.3
name: appwrite_dev
version: 0.3.2
description: Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API
homepage: https://appwrite.io
repository: https://github.com/appwrite/sdk-for-flutter-dev
@@ -9,30 +9,15 @@ environment:
sdk: '>=2.6.0 <3.0.0'
dependencies:
meta: ^1.1.8
path_provider: ^1.6.5
package_info: ^0.4.0+16
dio: ^3.0.0
cookie_jar: ^1.0.0
path_provider: ^1.6.14
package_info: ^0.4.3
dio: ^3.0.10
cookie_jar: ^1.0.1
dio_cookie_manager: ^1.0.0
flutter_web_auth: ^0.2.4
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
sdk: flutter
+9
View File
@@ -1,3 +1,12 @@
## 0.3.0-dev.2
- Fix for an error when using a self-signed certificate for Web
## 0.3.0-dev.1
- Updated package dependencies (@lohanidamodar)
- Added Flutter for Web compatibility (@lohanidamodar)
## 0.2.3
- Fixed OAuth2 cookie bug, where a new session cookie couldn&#039;t overwrite an old cookie
+1 -1
View File
@@ -20,7 +20,7 @@ Add this to your package's `pubspec.yaml` file:
```yml
dependencies:
appwrite: ^0.2.3
appwrite: ^0.3.0-dev.2
```
You can install packages from the command line:
+29 -17
View File
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:dio/adapter.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:cookie_jar/cookie_jar.dart';
@@ -20,17 +21,21 @@ class Client {
PersistCookieJar cookieJar;
Client({this.endPoint = 'https://appwrite.io/v1', this.selfSigned = false, Dio http}) : this.http = http ?? Dio() {
type = (Platform.isIOS) ? 'ios' : type;
type = (Platform.isMacOS) ? 'macos' : type;
type = (Platform.isAndroid) ? 'android' : type;
type = (Platform.isLinux) ? 'linux' : type;
type = (Platform.isWindows) ? 'windows' : type;
type = (Platform.isFuchsia) ? 'fuchsia' : type;
// Platform is not supported in web so if web, set type to web automatically and skip Platform check
if(kIsWeb) {
type = 'web';
}else{
type = (Platform.isIOS) ? 'ios' : type;
type = (Platform.isMacOS) ? 'macos' : type;
type = (Platform.isAndroid) ? 'android' : type;
type = (Platform.isLinux) ? 'linux' : type;
type = (Platform.isWindows) ? 'windows' : type;
type = (Platform.isFuchsia) ? 'fuchsia' : type;
}
this.headers = {
'content-type': 'application/json',
'x-sdk-version': 'appwrite:dart:0.2.3',
'x-sdk-version': 'appwrite:flutter:0.3.0-dev.2',
};
this.config = {};
@@ -78,22 +83,25 @@ class Client {
Future init() async {
if(!initialized) {
final Directory cookieDir = await _getCookiePath();
cookieJar = new PersistCookieJar(dir:cookieDir.path);
// if web skip cookie implementation and origin header as those are automatically handled by browsers
if(!kIsWeb) {
final Directory cookieDir = await _getCookiePath();
cookieJar = new PersistCookieJar(dir:cookieDir.path);
this.http.interceptors.add(CookieManager(cookieJar));
PackageInfo packageInfo = await PackageInfo.fromPlatform();
addHeader('Origin', 'appwrite-' + type + '://' + packageInfo.packageName);
}else{
// if web set httpClientAdapter as BrowserHttpClientAdapter with withCredentials true to make cookies work
this.http.options.extra['withCredentials'] = true;
}
this.http.options.baseUrl = this.endPoint;
this.http.options.validateStatus = (status) => status < 400;
this.http.interceptors.add(CookieManager(cookieJar));
PackageInfo packageInfo = await PackageInfo.fromPlatform();
addHeader('Origin', 'appwrite-' + type + '://' + packageInfo.packageName);
}
}
Future<Response> call(HttpMethod method, {String path = '', Map<String, String> headers = const {}, Map<String, dynamic> params = const {}}) async {
if(selfSigned) {
if(selfSigned && !kIsWeb) {
// Allow self signed requests
(http.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
@@ -114,6 +122,10 @@ class Client {
}
if (method == HttpMethod.get) {
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
return http.get(path, queryParameters: params, options: options);
} else {
return http.request(path, data: params, options: options);
@@ -1,8 +1,10 @@
import 'dart:io';
import 'package:universal_html/html.dart' as html;
import 'package:dio/dio.dart';
import 'package:meta/meta.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_web_auth/flutter_web_auth.dart';
import "../client.dart";
@@ -337,19 +339,26 @@ class Account extends Service {
query: query.join('&')
);
return FlutterWebAuth.authenticate(
url: url.toString(),
callbackUrlScheme: "appwrite-callback-" + client.config['project']
).then((value) async {
Uri url = Uri.parse(value);
Cookie cookie = new Cookie(url.queryParameters['key'], url.queryParameters['secret']);
cookie.domain = Uri.parse(client.endPoint).host;
cookie.httpOnly = true;
cookie.path = '/';
List<Cookie> cookies = [cookie];
await client.init();
client.cookieJar.saveFromResponse(Uri.parse(client.endPoint), cookies);
});
if(kIsWeb) {
html.window.location.href = url.toString();
return null;
}else{
return FlutterWebAuth.authenticate(
url: url.toString(),
callbackUrlScheme: "appwrite-callback-" + client.config['project']
).then((value) async {
Uri url = Uri.parse(value);
Cookie cookie = new Cookie(url.queryParameters['key'], url.queryParameters['secret']);
cookie.domain = Uri.parse(client.endPoint).host;
cookie.httpOnly = true;
cookie.path = '/';
List<Cookie> cookies = [cookie];
await client.init();
client.cookieJar.saveFromResponse(Uri.parse(client.endPoint), cookies);
});
}
}
/// Delete Account Session
@@ -376,16 +385,17 @@ class Account extends Service {
/// Use this endpoint to send a verification message to your user email address
/// to confirm they are the valid owners of that address. Both the **userId**
/// and **secret** arguments will be passed as query parameters to the URL you
/// have provider to be attached to the verification email. The provided URL
/// should redirect the user back for your app and allow you to complete the
/// have provided to be attached to the verification email. The provided URL
/// should redirect the user back to your app and allow you to complete the
/// verification process by verifying both the **userId** and **secret**
/// parameters. Learn more about how to [complete the verification
/// process](/docs/client/account#updateAccountVerification).
///
/// Please note that in order to avoid a [Redirect
/// Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md)
/// Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md),
/// the only valid redirect URLs are the ones from domains you have set when
/// adding your platforms in the console interface.
///
///
Future<Response> createVerification({@required String url}) {
final String path = '/account/verification';
@@ -27,6 +27,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -55,6 +59,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -79,6 +87,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -106,6 +118,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -134,6 +150,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -170,6 +190,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -186,7 +210,7 @@ class Avatars extends Service {
/// Converts a given plain text to a QR code image. You can use the query
/// parameters to change the size and style of the resulting image.
///
String getQR({@required String text, int size = 400, int margin = 1, int download = 0}) {
String getQR({@required String text, int size = 400, int margin = 1, bool download = false}) {
final String path = '/avatars/qr';
final Map<String, dynamic> params = {
@@ -197,6 +221,10 @@ class Avatars extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -17,7 +17,7 @@ class Database extends Service {
/// of the project documents. [Learn more about different API
/// modes](/docs/admin).
///
Future<Response> listDocuments({@required String collectionId, List filters = const [], int offset = 0, int limit = 50, String orderField = '\$id', OrderType orderType = OrderType.asc, String orderCast = 'string', String search = '', int first = 0, int last = 0}) {
Future<Response> listDocuments({@required String collectionId, List filters = const [], int offset = 0, int limit = 50, String orderField = '\$id', OrderType orderType = OrderType.asc, String orderCast = 'string', String search = ''}) {
final String path = '/database/collections/{collectionId}/documents'.replaceAll(RegExp('{collectionId}'), collectionId);
final Map<String, dynamic> params = {
@@ -28,8 +28,6 @@ class Database extends Service {
'orderType': orderType.name(),
'orderCast': orderCast,
'search': search,
'first': first,
'last': last,
};
final Map<String, String> headers = {
@@ -124,6 +124,10 @@ class Storage extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -154,6 +158,10 @@ class Storage extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
@@ -178,6 +186,10 @@ class Storage extends Service {
'project': client.config['project'],
};
params.keys.forEach((key) {if (params[key] is int || params[key] is double) {
params[key] = params[key].toString();
}});
Uri endpoint = Uri.parse(client.endPoint);
Uri location = new Uri(scheme: endpoint.scheme,
host: endpoint.host,
+7 -21
View File
@@ -1,5 +1,5 @@
name: appwrite
version: 0.2.3
version: 0.3.0-dev.2
description: Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API
homepage: https://appwrite.io
repository: https://github.com/appwrite/sdk-for-flutter
@@ -9,30 +9,16 @@ environment:
sdk: '>=2.6.0 <3.0.0'
dependencies:
meta: ^1.1.8
path_provider: ^1.6.5
package_info: ^0.4.0+16
dio: ^3.0.0
cookie_jar: ^1.0.0
path_provider: ^1.6.14
package_info: ^0.4.3
dio: ^3.0.10
cookie_jar: ^1.0.1
dio_cookie_manager: ^1.0.0
flutter_web_auth: ^0.2.4
universal_html: ^1.2.3
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
sdk: flutter
+1
View File
@@ -0,0 +1 @@
# Change Log
+12
View File
@@ -0,0 +1,12 @@
Copyright (c) 2019 Appwrite (https://appwrite.io) and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name Appwrite nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Some files were not shown because too many files have changed in this diff Show More