Compare commits

..
Author SHA1 Message Date
Everly Precia Suresh 434e2849d5 fix failing tests 2023-03-13 02:34:48 +00:00
Everly Precia Suresh cd7043ac58 Fix failing tests 2023-03-12 20:51:03 +00:00
Everly Precia Suresh b073c51bce regenerate tests 2023-03-12 19:15:14 +00:00
Everly Precia Suresh 170ef042fc resolve merge conflicts 2023-03-12 18:35:51 +00:00
Everly Precia Suresh dd8784d90e empty commit 2023-03-11 15:12:00 +00:00
Everly Precia Suresh 2f3501434d Merge branch 'master' of https://github.com/appwrite/appwrite into decouple-endpoints 2023-02-06 17:31:07 +00:00
Everly Precia Suresh cbdc9488bb generate specs 2023-01-19 19:02:22 +00:00
b5f3d38474 fix: change grammar
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-01-19 22:08:10 +05:30
a9d5931dd8 fix: change grammar
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-01-19 22:07:27 +05:30
Everly Precia Suresh dd00303b08 fix:additional tests 2023-01-17 02:30:59 +00:00
Everly Precia Suresh 29ae4f4540 Merge branch 'master' of https://github.com/appwrite/appwrite into decouple-endpoints 2023-01-16 18:58:30 +00:00
Everly Precia Suresh 03a89453ed style:run linter 2023-01-16 18:32:52 +00:00
Everly Precia Suresh f57493e291 fix tests 2023-01-16 17:46:57 +00:00
Everly Precia Suresh fcd67300ef Push changes 2023-01-13 17:36:54 +00:00
Everly Precia Suresh ffc8615002 Push changes 2023-01-13 17:34:11 +00:00
Everly Precia Suresh a59fe0b701 fix tests 2023-01-12 18:38:21 +00:00
Everly Precia Suresh 38d2b7bb17 decouple projects endpoint 2022-12-21 18:50:43 +00:00
Everly Precia Suresh 7d0067df54 decouple projects endpoint 2022-12-21 18:27:26 +00:00
2849 changed files with 1300 additions and 59656 deletions
-53
View File
@@ -1,53 +0,0 @@
name: "Release"
on:
release:
types: [published]
jobs:
tests:
name: Unit & E2E
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
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
# Fetch submodules
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: appwrite/appwrite
tags: |
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.{{minor}}.{{patch}}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ steps.meta.outputs.version }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "app/console"]
path = app/console
url = https://github.com/appwrite/console
branch = 2.3.3
branch = 2.2.0
+2 -24
View File
@@ -1,28 +1,6 @@
# Version 1.3.1
## Bugs
- Fixed Migration issue regarding 500 error [4906](https://github.com/appwrite/appwrite/pull/5356)
# Version 1.3.0
## Features
- Password dictionary setting allows to compare user's password against command password database [4906](https://github.com/appwrite/appwrite/pull/4906)
- Password history setting allows to save user's last used password so that it may not be used again. Maximum number of history saved is 20, which can be configured. Minimum is 0 which means disabled. [#4866](https://github.com/appwrite/appwrite/pull/4866)
- Update APIs to check X-Appwrite-Timestamp header [#5024](https://github.com/appwrite/appwrite/pull/5024)
- Database relationships [#5238](https://github.com/appwrite/appwrite/pull/5238)
- New query operators [#5238](https://github.com/appwrite/appwrite/pull/5238)
- Team preferences [#5196](https://github.com/appwrite/appwrite/pull/5196)
- Update attribute metadata [#5164](https://github.com/appwrite/appwrite/pull/5164)
## Bugs
- Fix not storing function's response on response codes 5xx [#4610](https://github.com/appwrite/appwrite/pull/4610)
# Version TBD
- Fix expire to formatTz in create account session [#4985](https://github.com/appwrite/appwrite/pull/4985)
- Fix deleting projects when organization is deleted [#5335](https://github.com/appwrite/appwrite/pull/5335)
- Fix deleting collections from a project [#4983](https://github.com/appwrite/appwrite/pull/4983)
- Fix cleaning up project databases [#4984](https://github.com/appwrite/appwrite/pull/4984)
- Fix creating documents with attributes with special characters [#246](https://github.com/utopia-php/database/pull/246)
- Fix deleting attribute not deleting metadata index [#246](https://github.com/utopia-php/database/pull/246)
- Fix create attribute event payload [#246](https://github.com/utopia-php/database/pull/246)
- Fix not storing function's response on response codes 5xx [#4610](https://github.com/appwrite/appwrite/pull/4610)
# Version 1.2.1
## Changes
+2 -9
View File
@@ -346,7 +346,8 @@ If you are in PHP Storm you don't need any plugin. Below are the settings requir
1. Create an init file.
2. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php**.
3. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
3. Change the IP address to your development machine's IP. Without the proper IP address, the debugger won't connect.
4. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
### VS Code Launch Configuration
@@ -435,14 +436,6 @@ composer lint
composer lint <your file path>
```
## Clearing the Cache
If you need to clear the cache, you can do so by running the following command:
```bash
docker compose exec redis redis-cli FLUSHALL
```
## Tutorials
From time to time, our team will add tutorials that will help contributors find their way in the Appwrite source code. Below is a list of currently available tutorials:
+3 -3
View File
@@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM --platform=$BUILDPLATFORM node:16.14.2-alpine3.15 as node
FROM node:16.14.2-alpine3.15 as node
COPY app/console /usr/local/src/console
@@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT
RUN npm ci
RUN npm run build
FROM appwrite/base:0.2.2 as final
FROM appwrite/base:0.1.0 as final
LABEL maintainer="team@appwrite.io"
@@ -182,7 +182,7 @@ RUN chmod +x /usr/local/bin/doctor && \
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/src/code/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi
RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/local/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi
RUN if [ "$DEBUG" == "true" ]; then echo "opcache.enable=0" >> /usr/local/etc/php/conf.d/appwrite.ini; fi
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
+5 -5
View File
@@ -12,7 +12,7 @@
</p>
<!-- [![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite) -->
[![We're Hiring](https://img.shields.io/static/v1?label=We're&message=Hiring&color=blue&style=flat-square)](https://appwrite.io/company/careers)
[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=friendly&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github)
[![Build Status](https://img.shields.io/github/actions/workflow/status/appwrite/appwrite/tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions)
@@ -24,7 +24,7 @@
[English](README.md) | 简体中文
[**宣布带有数据库关系的 Appwrite 1.3!了解最新消息!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
[**我们发布了 Appwrite Console 2.0 版本,点击这里了解更多!**](https://medium.com/appwrite-io/announcing-console-2-0-2e0e96891cb0?source=friends_link&sk=7a82b4069778e3adc165dc026e960fe1)
Appwrite是一个基于Docker的端到端开发者平台,其容器化的微服务库可应用于网页端,移动端,以及后端。Appwrite 通过视觉化界面简化了从零开始编写 API 的繁琐过程,在保证软件安全的前提下为开发者创造了一个高效的开发环境。
@@ -67,7 +67,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.3.1
appwrite/appwrite:1.2.1
```
### Windows
@@ -79,7 +79,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.3.1
appwrite/appwrite:1.2.1
```
#### PowerShell
@@ -89,7 +89,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.3.1
appwrite/appwrite:1.2.1
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
+4 -5
View File
@@ -14,7 +14,6 @@
<!-- [![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite) -->
[![We're Hiring](https://img.shields.io/static/v1?label=We're&message=Hiring&color=blue&style=flat-square)](https://appwrite.io/company/careers)
[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=ready&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github)
[![Build Status](https://img.shields.io/github/actions/workflow/status/appwrite/appwrite/tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions)
@@ -26,7 +25,7 @@
English | [简体中文](README-CN.md)
[**Announcing Appwrite 1.3 with Database Relationships! Learn what's new!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
[**Announcing Appwrite 1.2 with GraphQL support! Learn what's new!**](https://appwrite.io/graphql)
Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps packaged as a set of Docker<nobr> microservices. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.
@@ -76,7 +75,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.3.1
appwrite/appwrite:1.2.1
```
### Windows
@@ -88,7 +87,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.3.1
appwrite/appwrite:1.2.1
```
#### PowerShell
@@ -98,7 +97,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.3.1
appwrite/appwrite:1.2.1
```
Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation.
+2 -2
View File
@@ -4,11 +4,11 @@
| Version | Supported |
| --------- | ------------------ |
| <= 0.15.x | :x: |
| <= 0.14.x | :x: |
| 0.15.x | :white_check_mark: |
| 1.0.x | :white_check_mark: |
| 1.1.x | :white_check_mark: |
| 1.2.x | :white_check_mark: |
| 1.3.x | :white_check_mark: |
## Reporting a Vulnerability
File diff suppressed because it is too large Load Diff
-32
View File
@@ -346,16 +346,6 @@ $collections = [
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('options'),
'type' => Database::VAR_STRING,
'size' => 16384,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['json'],
],
],
'indexes' => [
[
@@ -1244,17 +1234,6 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('passwordHistory'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('password'),
'type' => Database::VAR_STRING,
@@ -1875,17 +1854,6 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('prefs'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 65535,
'signed' => true,
'required' => false,
'default' => new \stdClass(),
'array' => false,
'filters' => ['json'],
],
],
'indexes' => [
[
+3 -23
View File
@@ -408,16 +408,6 @@ return [
'description' => 'Document with the requested ID already exists.',
'code' => 409,
],
Exception::DOCUMENT_UPDATE_CONFLICT => [
'name' => Exception::DOCUMENT_UPDATE_CONFLICT,
'description' => 'Remote document is newer than local.',
'code' => 409,
],
Exception::DOCUMENT_DELETE_RESTRICTED => [
'name' => Exception::DOCUMENT_DELETE_RESTRICTED,
'description' => 'Document cannot be deleted because it is referenced by another document.',
'code' => 403,
],
/** Attributes */
Exception::ATTRIBUTE_NOT_FOUND => [
@@ -427,12 +417,12 @@ return [
],
Exception::ATTRIBUTE_UNKNOWN => [
'name' => Exception::ATTRIBUTE_UNKNOWN,
'description' => 'The attribute required for the index could not be found. Please confirm all your attributes are in the available state.',
'description' => 'The attribute required for the index could not be found. Please confirm all your attributes are in the <span class="tag">available</span> state.',
'code' => 400,
],
Exception::ATTRIBUTE_NOT_AVAILABLE => [
'name' => Exception::ATTRIBUTE_NOT_AVAILABLE,
'description' => 'The requested attribute is not yet available. Please try again later.',
'description' => 'The requested attribute is not yet <span class="tag">available</span>. Please try again later.',
'code' => 400,
],
Exception::ATTRIBUTE_FORMAT_UNSUPPORTED => [
@@ -442,7 +432,7 @@ return [
],
Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED => [
'name' => Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED,
'description' => 'Default values cannot be set for array or required attributes.',
'description' => 'Default values cannot be set for <span class="tag">array</span> and <span class="tag">required</span> attributes.',
'code' => 400,
],
Exception::ATTRIBUTE_ALREADY_EXISTS => [
@@ -460,11 +450,6 @@ return [
'description' => 'The attribute value is invalid. Please check the type, range and value of the attribute.',
'code' => 400,
],
Exception::ATTRIBUTE_TYPE_INVALID => [
'name' => Exception::ATTRIBUTE_TYPE_INVALID,
'description' => 'The attribute type is invalid.',
'code' => 400,
],
/** Indexes */
Exception::INDEX_NOT_FOUND => [
@@ -564,11 +549,6 @@ return [
'description' => 'Domain verification for the requested domain has failed.',
'code' => 401,
],
Exception::DOMAIN_TARGET_INVALID => [
'name' => Exception::DOMAIN_TARGET_INVALID,
'description' => 'Your Appwrite instance is not publicly accessible. Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.',
'code' => 501,
],
Exception::GRAPHQL_NO_QUERY => [
'name' => Exception::GRAPHQL_NO_QUERY,
'description' => 'Param "query" is not optional.',
+3 -6
View File
@@ -183,16 +183,13 @@ return [
],
],
'create' => [
'$description' => 'This event triggers when a team is created.'
'$description' => 'This event triggers when a bucket is created.'
],
'delete' => [
'$description' => 'This event triggers when a team is deleted.',
'$description' => 'This event triggers when a bucket is deleted.',
],
'update' => [
'$description' => 'This event triggers when a team is updated.',
'prefs' => [
'$description' => 'This event triggers when a team\'s preferences are updated.',
],
'$description' => 'This event triggers when a bucket is updated.',
]
],
'functions' => [
+17 -17
View File
@@ -15,7 +15,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '11.0.0',
'version' => '10.2.0',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@@ -63,7 +63,7 @@ return [
[
'key' => 'flutter',
'name' => 'Flutter',
'version' => '9.0.0',
'version' => '8.2.0',
'url' => 'https://github.com/appwrite/sdk-for-flutter',
'package' => 'https://pub.dev/packages/appwrite',
'enabled' => true,
@@ -81,7 +81,7 @@ return [
[
'key' => 'apple',
'name' => 'Apple',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-apple',
'package' => 'https://github.com/appwrite/sdk-for-apple',
'enabled' => true,
@@ -116,7 +116,7 @@ return [
[
'key' => 'android',
'name' => 'Android',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-android',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
'enabled' => true,
@@ -185,7 +185,7 @@ return [
[
'key' => 'web',
'name' => 'Console',
'version' => '0.1.0',
'version' => '0.0.1',
'url' => 'https://github.com/appwrite/sdk-for-console',
'package' => '',
'enabled' => true,
@@ -203,7 +203,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '2.0.0',
'version' => '1.1.1',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@@ -231,7 +231,7 @@ return [
[
'key' => 'nodejs',
'name' => 'Node.js',
'version' => '9.0.0',
'version' => '8.2.0',
'url' => 'https://github.com/appwrite/sdk-for-node',
'package' => 'https://www.npmjs.com/package/node-appwrite',
'enabled' => true,
@@ -249,7 +249,7 @@ return [
[
'key' => 'deno',
'name' => 'Deno',
'version' => '7.0.0',
'version' => '6.2.0',
'url' => 'https://github.com/appwrite/sdk-for-deno',
'package' => 'https://deno.land/x/appwrite',
'enabled' => true,
@@ -267,7 +267,7 @@ return [
[
'key' => 'php',
'name' => 'PHP',
'version' => '8.0.0',
'version' => '7.2.0',
'url' => 'https://github.com/appwrite/sdk-for-php',
'package' => 'https://packagist.org/packages/appwrite/appwrite',
'enabled' => true,
@@ -285,7 +285,7 @@ return [
[
'key' => 'python',
'name' => 'Python',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-python',
'package' => 'https://pypi.org/project/appwrite/',
'enabled' => true,
@@ -303,7 +303,7 @@ return [
[
'key' => 'ruby',
'name' => 'Ruby',
'version' => '8.0.0',
'version' => '7.2.0',
'url' => 'https://github.com/appwrite/sdk-for-ruby',
'package' => 'https://rubygems.org/gems/appwrite',
'enabled' => true,
@@ -321,7 +321,7 @@ return [
[
'key' => 'go',
'name' => 'Go',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-go',
'package' => '',
'enabled' => false,
@@ -339,7 +339,7 @@ return [
[
'key' => 'java',
'name' => 'Java',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-java',
'package' => '',
'enabled' => false,
@@ -357,7 +357,7 @@ return [
[
'key' => 'dotnet',
'name' => '.NET',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
'package' => 'https://www.nuget.org/packages/Appwrite',
'enabled' => false,
@@ -375,7 +375,7 @@ return [
[
'key' => 'dart',
'name' => 'Dart',
'version' => '8.0.0',
'version' => '7.2.0',
'url' => 'https://github.com/appwrite/sdk-for-dart',
'package' => 'https://pub.dev/packages/dart_appwrite',
'enabled' => true,
@@ -393,7 +393,7 @@ return [
[
'key' => 'kotlin',
'name' => 'Kotlin',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
'enabled' => true,
@@ -415,7 +415,7 @@ return [
[
'key' => 'swift',
'name' => 'Swift',
'version' => '2.0.0',
'version' => '1.2.0',
'url' => 'https://github.com/appwrite/sdk-for-swift',
'package' => 'https://github.com/appwrite/sdk-for-swift',
'enabled' => true,
+4 -2
View File
@@ -14,8 +14,10 @@ $member = [
'documents.write',
'files.read',
'files.write',
'projects.read',
'projects.write',
'project.read',
'project.write',
'admin.read',
'admin.write',
'locale.read',
'avatars.read',
'execution.read',
+23 -23
View File
@@ -1,9 +1,9 @@
<?php
return [
'web/home' => [
'key' => 'web/home',
'name' => 'Home',
'/' => [
'key' => 'homepage',
'name' => 'Homepage',
'subtitle' => '',
'description' => '',
'controller' => 'web/home.php',
@@ -14,8 +14,8 @@ return [
'optional' => false,
'icon' => '',
],
'web/console' => [
'key' => 'web/console',
'console' => [
'key' => 'console',
'name' => 'Console',
'subtitle' => '',
'description' => '',
@@ -95,12 +95,25 @@ return [
'optional' => true,
'icon' => '/images/services/health.png',
],
'projects' => [
'key' => 'projects',
'name' => 'Projects',
'subtitle' => 'The Project service allows you to manage all the projects in your Appwrite server.',
'admin' => [
'key' => 'admin',
'name' => 'admin',
'subtitle' => 'The Admin service allows you to manage all the projects in your Appwrite server.',
'description' => '',
'controller' => 'api/projects.php',
'controller' => 'api/admin.php',
'sdk' => true,
'docs' => true,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
'project' => [
'key' => 'project',
'name' => 'Project',
'subtitle' => 'The Project service allows you to manage a specific project on your Appwrite server.',
'description' => '',
'controller' => 'api/project.php',
'sdk' => true,
'docs' => true,
'docsUrl' => '',
@@ -186,17 +199,4 @@ return [
'optional' => true,
'icon' => '/images/services/graphql.png',
],
'console' => [
'key' => 'console',
'name' => 'Console',
'subtitle' => 'The Console service allows you to interact with console relevant informations.',
'description' => '',
'controller' => 'api/console.php',
'sdk' => true,
'docs' => true,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
];
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
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
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
+1 -1
View File
@@ -764,7 +764,7 @@ return [
],
[
'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD',
'description' => 'The minimum time a function must be inactive before it can be shut down and cleaned up. This feature is intended to clean up unused containers. Containers may remain active for longer than the interval before being shut down, as Appwrite only cleans up unused containers every hour. If no value is provided, the default is 60 seconds.',
'description' => 'The minimum time a function can be inactive before it\'s container is shutdown and put to sleep. The default value is 60 seconds',
'introduction' => '0.13.0',
'default' => '60',
'required' => false,
+38 -78
View File
@@ -40,8 +40,6 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Appwrite\Auth\Validator\PasswordHistory;
use Appwrite\Auth\Validator\PasswordDictionary;
$oauthDefaultSuccess = '/auth/oauth2/success';
$oauthDefaultFailure = '/auth/oauth2/failure';
@@ -62,11 +60,11 @@ App::post('/v1/account')
->label('sdk.description', '/docs/references/account/create.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('abuse-limit', 10)
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', '', new Email(), 'User email.')
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('request')
->inject('response')
@@ -74,6 +72,7 @@ App::post('/v1/account')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $project, Database $dbForProject, Event $events) {
$email = \strtolower($email);
if ('console' === $project->getId()) {
$whitelistEmails = $project->getAttribute('authWhitelistEmails');
@@ -98,8 +97,6 @@ App::post('/v1/account')
}
}
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
$password = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
try {
$userId = $userId == 'unique()' ? ID::unique() : $userId;
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
@@ -112,11 +109,10 @@ App::post('/v1/account')
'email' => $email,
'emailVerification' => false,
'status' => true,
'password' => $password,
'passwordHistory' => $passwordHistory > 0 ? [$password] : [],
'passwordUpdate' => DateTime::now(),
'password' => Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS),
'hash' => Auth::DEFAULT_ALGO,
'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS,
'passwordUpdate' => DateTime::now(),
'registration' => DateTime::now(),
'reset' => false,
'name' => $name,
@@ -505,11 +501,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
}
}
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
try {
$userId = ID::unique();
$password = Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
'$id' => $userId,
'$permissions' => [
@@ -520,8 +513,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'email' => $email,
'emailVerification' => true,
'status' => true, // Email should already be authenticated by OAuth2 provider
'passwordHistory' => $passwordHistory > 0 ? [$password] : null,
'password' => $password,
'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS),
'hash' => Auth::DEFAULT_ALGO,
'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS,
'passwordUpdate' => null,
@@ -1328,7 +1320,7 @@ App::get('/v1/account')
->label('sdk.description', '/docs/references/account/get.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->inject('response')
@@ -1356,7 +1348,7 @@ App::get('/v1/account/prefs')
->inject('user')
->action(function (Response $response, Document $user) {
$prefs = $user->getAttribute('prefs', []);
$prefs = $user->getAttribute('prefs', new \stdClass());
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
@@ -1411,7 +1403,7 @@ App::get('/v1/account/logs')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
->inject('response')
->inject('user')
->inject('locale')
@@ -1520,22 +1512,19 @@ App::patch('/v1/account/name')
->label('sdk.description', '/docs/references/account/update-name.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $name, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $name, Response $response, Document $user, Database $dbForProject, Event $events) {
$user
$user = $dbForProject->updateDocument('users', $user->getId(), $user
->setAttribute('name', $name)
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email', ''), $user->getAttribute('phone', '')]));
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email', ''), $user->getAttribute('phone', '')])));
$events->setParam('userId', $user->getId());
@@ -1557,46 +1546,27 @@ App::patch('/v1/account/password')
->label('sdk.description', '/docs/references/account/update-password.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->param('password', '', new Password(), 'New user password. Must be at least 8 chars.')
->param('oldPassword', '', new Password(), 'Current user password. Must be at least 8 chars.', true)
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $password, string $oldPassword, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) {
->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Event $events) {
// Check old password only if its an existing user.
if (!empty($user->getAttribute('passwordUpdate')) && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
}
$newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
$historyLimit = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
$history = [];
if ($historyLimit > 0) {
$history = $user->getAttribute('passwordHistory', []);
$validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions'));
if (!$validator->isValid($password)) {
throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409);
}
$history[] = $newPassword;
array_slice($history, (count($history) - $historyLimit), $historyLimit);
}
$user
->setAttribute('password', $newPassword)
->setAttribute('passwordHistory', $history)
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$user = $dbForProject->updateDocument('users', $user->getId(), $user
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now()));
$events->setParam('userId', $user->getId());
@@ -1618,17 +1588,16 @@ App::patch('/v1/account/email')
->label('sdk.description', '/docs/references/account/update-email.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Event $events) {
$isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting
if (
@@ -1649,7 +1618,7 @@ App::patch('/v1/account/email')
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $email, $user->getAttribute('phone', '')]));
try {
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
} catch (Duplicate $th) {
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
}
@@ -1674,17 +1643,16 @@ App::patch('/v1/account/phone')
->label('sdk.description', '/docs/references/account/update-phone.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Event $events) {
$isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting
@@ -1701,7 +1669,7 @@ App::patch('/v1/account/phone')
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $user->getAttribute('email', ''), $phone]));
try {
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
} catch (Duplicate $th) {
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
}
@@ -1726,20 +1694,17 @@ App::patch('/v1/account/prefs')
->label('sdk.description', '/docs/references/account/update-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.offline.model', '/account/prefs')
->label('sdk.offline.key', 'current')
->param('prefs', [], new Assoc(), 'Prefs key-value JSON object.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (array $prefs, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Event $events) {
$user->setAttribute('prefs', $prefs);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
$events->setParam('userId', $user->getId());
@@ -1761,17 +1726,15 @@ App::patch('/v1/account/status')
->label('sdk.description', '/docs/references/account/update-status.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->inject('requestTimestamp')
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->inject('request')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
$user->setAttribute('status', false);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
$events
->setParam('userId', $user->getId())
@@ -1801,7 +1764,6 @@ App::delete('/v1/account/sessions/:sessionId')
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to delete the current device session.')
->inject('requestTimestamp')
->inject('request')
->inject('response')
->inject('user')
@@ -1809,7 +1771,7 @@ App::delete('/v1/account/sessions/:sessionId')
->inject('locale')
->inject('events')
->inject('project')
->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) {
->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) {
$protocol = $request->getProtocol();
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
@@ -1821,12 +1783,10 @@ App::delete('/v1/account/sessions/:sessionId')
foreach ($sessions as $key => $session) {/** @var Document $session */
if ($sessionId == $session->getId()) {
$dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $session) {
return $dbForProject->deleteDocument('sessions', $session->getId());
});
unset($sessions[$key]);
$dbForProject->deleteDocument('sessions', $session->getId());
$session->setAttribute('current', false);
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
@@ -2186,9 +2146,9 @@ App::put('/v1/account/recovery')
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('emailVerification', true));
$recoveryDocument = $dbForProject->getDocument('tokens', $recovery);
+55
View File
@@ -0,0 +1,55 @@
<?php
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
use Utopia\Validator\Text;
App::get('/v1/admin')
->desc('List Projects')
->groups(['api', 'admin'])
->label('scope', 'admin.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'admin')
->label('sdk.method', 'listProjects')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForConsole')
->action(function (array $queries, string $search, Response $response, Database $dbForConsole) {
$queries = Query::parseQueries($queries);
if (!empty($search)) {
$queries[] = Query::search('search', $search);
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
$projectId = $cursor->getValue();
$cursorDocument = $dbForConsole->getDocument('projects', $projectId);
if ($cursorDocument->isEmpty()) {
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Project '{$projectId}' for the 'cursor' value not found.");
}
$cursor->setValue($cursorDocument);
}
$filterQueries = Query::groupByType($queries)['filters'];
$response->dynamic(new Document([
'projects' => $dbForConsole->find('projects', $queries),
'total' => $dbForConsole->count('projects', $filterQueries, APP_LIMIT_COUNT),
]), Response::MODEL_PROJECT_LIST);
});
-40
View File
@@ -1,40 +0,0 @@
<?php
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Database\Document;
App::init()
->groups(['console'])
->inject('project')
->action(function (Document $project) {
if ($project->getId() !== 'console') {
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN);
}
});
App::get('/v1/console/variables')
->desc('Get Variables')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'console')
->label('sdk.method', 'variables')
->label('sdk.description', '/docs/references/console/variables.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES)
->inject('response')
->action(function (Response $response) {
$variables = new Document([
'_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'),
'_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'),
'_APP_FUNCTIONS_SIZE_LIMIT' => +App::getEnv('_APP_FUNCTIONS_SIZE_LIMIT'),
'_APP_USAGE_STATS' => App::getEnv('_APP_USAGE_STATS'),
]);
$response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES);
});
File diff suppressed because it is too large Load Diff
+11 -9
View File
@@ -25,6 +25,7 @@ use Appwrite\Task\Validator\Cron;
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
use Appwrite\Utopia\Database\Validator\Queries\Executions;
use Appwrite\Utopia\Database\Validator\Queries\Functions;
use Appwrite\Utopia\Database\Validator\Queries\Variables;
use Utopia\App;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -32,6 +33,7 @@ use Utopia\Database\DateTime;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
@@ -61,7 +63,7 @@ App::post('/v1/functions')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
@@ -123,7 +125,7 @@ App::get('/v1/functions')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION_LIST)
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -438,7 +440,7 @@ App::put('/v1/functions/:functionId')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function ID.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true)
@@ -599,8 +601,8 @@ App::post('/v1/functions/:functionId/deployments')
->label('sdk.response.model', Response::MODEL_DEPLOYMENT)
->param('functionId', '', new UID(), 'Function ID.')
->param('entrypoint', '', new Text('1028'), 'Entrypoint File.')
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true)
->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.')
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.', false)
->inject('request')
->inject('response')
->inject('dbForProject')
@@ -789,7 +791,7 @@ App::get('/v1/functions/:functionId/deployments')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST)
->param('functionId', '', new UID(), 'Function ID.')
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -1221,7 +1223,7 @@ App::get('/v1/functions/:functionId/executions')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_EXECUTION_LIST)
->param('functionId', '', new UID(), 'Function ID.')
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -1346,7 +1348,7 @@ App::post('/v1/functions/:functionId/variables')
->label('sdk.response.model', Response::MODEL_VARIABLE)
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', false)
->inject('response')
->inject('dbForProject')
->action(function (string $functionId, string $key, string $value, Response $response, Database $dbForProject) {
@@ -1462,7 +1464,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', true)
->inject('response')
->inject('dbForProject')
->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject) {
+1 -1
View File
@@ -30,7 +30,7 @@ App::get('/v1/graphql')
->label('sdk.response.model', Response::MODEL_ANY)
->label('abuse-limit', 60)
->label('abuse-time', 60)
->param('query', '', new Text(0, 0), 'The query to execute.')
->param('query', '', new Text(0), 'The query to execute.')
->param('operationName', '', new Text(256), 'The name of the operation to execute.', true)
->param('variables', '', new Text(0), 'The JSON encoded variables to use in the query.', true)
->inject('request')
@@ -23,12 +23,11 @@ use Utopia\Database\Helpers\Permission;
use Utopia\Database\Query;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\DatetimeValidator;
use Utopia\Database\Validator\UID;
use Utopia\Domains\Domain;
use Utopia\Registry\Registry;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Hostname;
@@ -37,7 +36,7 @@ use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
App::init()
->groups(['projects'])
->groups(['project'])
->inject('project')
->action(function (Document $project) {
if ($project->getId() !== 'console') {
@@ -45,12 +44,12 @@ App::init()
}
});
App::post('/v1/projects')
App::post('/v1/project')
->desc('Create Project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'create')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -80,7 +79,7 @@ App::post('/v1/projects')
}
$auth = Config::getParam('auth', []);
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'passwordHistory' => 0, 'passwordDictionary' => false, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG];
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG];
foreach ($auth as $index => $method) {
$auths[$method['key'] ?? ''] = true;
}
@@ -174,57 +173,12 @@ App::post('/v1/projects')
->dynamic($project, Response::MODEL_PROJECT);
});
App::get('/v1/projects')
->desc('List Projects')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'list')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForConsole')
->action(function (array $queries, string $search, Response $response, Database $dbForConsole) {
$queries = Query::parseQueries($queries);
if (!empty($search)) {
$queries[] = Query::search('search', $search);
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
$projectId = $cursor->getValue();
$cursorDocument = $dbForConsole->getDocument('projects', $projectId);
if ($cursorDocument->isEmpty()) {
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Project '{$projectId}' for the 'cursor' value not found.");
}
$cursor->setValue($cursorDocument);
}
$filterQueries = Query::groupByType($queries)['filters'];
$response->dynamic(new Document([
'projects' => $dbForConsole->find('projects', $queries),
'total' => $dbForConsole->count('projects', $filterQueries, APP_LIMIT_COUNT),
]), Response::MODEL_PROJECT_LIST);
});
App::get('/v1/projects/:projectId')
App::get('/v1/project/:projectId')
->desc('Get Project')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'get')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -243,12 +197,12 @@ App::get('/v1/projects/:projectId')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::get('/v1/projects/:projectId/usage')
App::get('/v1/project/:projectId/usage')
->desc('Get usage stats for a project')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'getUsage')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -357,12 +311,12 @@ App::get('/v1/projects/:projectId/usage')
$response->dynamic($usage, Response::MODEL_USAGE_PROJECT);
});
App::patch('/v1/projects/:projectId')
App::patch('/v1/project/:projectId')
->desc('Update Project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'update')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -404,12 +358,14 @@ App::patch('/v1/projects/:projectId')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/service')
App::patch('/v1/project/:projectId/service')
->desc('Update service status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateServiceStatus')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -435,12 +391,12 @@ App::patch('/v1/projects/:projectId/service')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/oauth2')
App::patch('/v1/project/:projectId/oauth2')
->desc('Update Project OAuth2')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateOAuth2')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -479,12 +435,12 @@ App::patch('/v1/projects/:projectId/oauth2')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/limit')
App::patch('/v1/project/:projectId/auth/limit')
->desc('Update Project users limit')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateAuthLimit')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -510,12 +466,12 @@ App::patch('/v1/projects/:projectId/auth/limit')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/duration')
App::patch('/v1/project/:projectId/auth/duration')
->desc('Update Project Authentication Duration')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateAuthDuration')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -541,12 +497,12 @@ App::patch('/v1/projects/:projectId/auth/duration')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/:method')
App::patch('/v1/project/:projectId/auth/:method')
->desc('Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateAuthStatus')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -575,74 +531,12 @@ App::patch('/v1/projects/:projectId/auth/:method')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/password-history')
->desc('Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthPasswordHistory')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['passwordHistory'] = $limit;
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/password-dictionary')
->desc('Update authentication password disctionary status. Use this endpoint to enable or disable the dicitonary check for user password')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthPasswordDictionary')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('enabled', false, new Boolean(false), 'Set whether or not to enable checking user\'s password against most commonly used passwords. Default is false.')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['passwordDictionary'] = $enabled;
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/max-sessions')
App::patch('/v1/project/:projectId/auth/max-sessions')
->desc('Update Project user sessions limit')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateAuthSessionsLimit')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -668,12 +562,12 @@ App::patch('/v1/projects/:projectId/auth/max-sessions')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::delete('/v1/projects/:projectId')
App::delete('/v1/project/:projectId')
->desc('Delete Project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'delete')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
@@ -709,12 +603,12 @@ App::delete('/v1/projects/:projectId')
// Webhooks
App::post('/v1/projects/:projectId/webhooks')
App::post('/v1/project/:projectId/webhooks')
->desc('Create Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'createWebhook')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -765,12 +659,12 @@ App::post('/v1/projects/:projectId/webhooks')
->dynamic($webhook, Response::MODEL_WEBHOOK);
});
App::get('/v1/projects/:projectId/webhooks')
App::get('/v1/project/:projectId/webhooks')
->desc('List Webhooks')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'listWebhooks')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -797,12 +691,12 @@ App::get('/v1/projects/:projectId/webhooks')
]), Response::MODEL_WEBHOOK_LIST);
});
App::get('/v1/projects/:projectId/webhooks/:webhookId')
App::get('/v1/project/:projectId/webhooks/:webhookId')
->desc('Get Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'getWebhook')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -831,12 +725,12 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
App::put('/v1/projects/:projectId/webhooks/:webhookId')
App::put('/v1/project/:projectId/webhooks/:webhookId')
->desc('Update Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateWebhook')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -885,12 +779,12 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
App::patch('/v1/project/:projectId/webhooks/:webhookId/signature')
->desc('Update Webhook Signature Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateWebhookSignature')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -924,12 +818,12 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
App::delete('/v1/projects/:projectId/webhooks/:webhookId')
App::delete('/v1/project/:projectId/webhooks/:webhookId')
->desc('Delete Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'deleteWebhook')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
@@ -963,12 +857,12 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
// Keys
App::post('/v1/projects/:projectId/keys')
App::post('/v1/project/:projectId/keys')
->desc('Create Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'createKey')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1013,12 +907,12 @@ App::post('/v1/projects/:projectId/keys')
->dynamic($key, Response::MODEL_KEY);
});
App::get('/v1/projects/:projectId/keys')
App::get('/v1/project/:projectId/keys')
->desc('List Keys')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'listKeys')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1045,12 +939,12 @@ App::get('/v1/projects/:projectId/keys')
]), Response::MODEL_KEY_LIST);
});
App::get('/v1/projects/:projectId/keys/:keyId')
App::get('/v1/project/:projectId/keys/:keyId')
->desc('Get Key')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'getKey')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1079,12 +973,12 @@ App::get('/v1/projects/:projectId/keys/:keyId')
$response->dynamic($key, Response::MODEL_KEY);
});
App::put('/v1/projects/:projectId/keys/:keyId')
App::put('/v1/project/:projectId/keys/:keyId')
->desc('Update Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateKey')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1126,12 +1020,12 @@ App::put('/v1/projects/:projectId/keys/:keyId')
$response->dynamic($key, Response::MODEL_KEY);
});
App::delete('/v1/projects/:projectId/keys/:keyId')
App::delete('/v1/project/:projectId/keys/:keyId')
->desc('Delete Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'deleteKey')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
@@ -1165,12 +1059,12 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
// Platforms
App::post('/v1/projects/:projectId/platforms')
App::post('/v1/project/:projectId/platforms')
->desc('Create Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'createPlatform')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1215,12 +1109,12 @@ App::post('/v1/projects/:projectId/platforms')
->dynamic($platform, Response::MODEL_PLATFORM);
});
App::get('/v1/projects/:projectId/platforms')
App::get('/v1/project/:projectId/platforms')
->desc('List Platforms')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'listPlatforms')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1247,12 +1141,12 @@ App::get('/v1/projects/:projectId/platforms')
]), Response::MODEL_PLATFORM_LIST);
});
App::get('/v1/projects/:projectId/platforms/:platformId')
App::get('/v1/project/:projectId/platforms/:platformId')
->desc('Get Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'getPlatform')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1281,12 +1175,12 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
$response->dynamic($platform, Response::MODEL_PLATFORM);
});
App::put('/v1/projects/:projectId/platforms/:platformId')
App::put('/v1/project/:projectId/platforms/:platformId')
->desc('Update Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updatePlatform')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1329,12 +1223,12 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
$response->dynamic($platform, Response::MODEL_PLATFORM);
});
App::delete('/v1/projects/:projectId/platforms/:platformId')
App::delete('/v1/project/:projectId/platforms/:platformId')
->desc('Delete Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'deletePlatform')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
@@ -1368,12 +1262,12 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
// Domains
App::post('/v1/projects/:projectId/domains')
App::post('/v1/project/:projectId/domains')
->desc('Create Domain')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'createDomain')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1402,7 +1296,7 @@ App::post('/v1/projects/:projectId/domains')
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
if (!$target->isKnown() || $target->isTest()) {
throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.');
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
}
$domain = new Domain($domain);
@@ -1433,12 +1327,12 @@ App::post('/v1/projects/:projectId/domains')
->dynamic($domain, Response::MODEL_DOMAIN);
});
App::get('/v1/projects/:projectId/domains')
App::get('/v1/project/:projectId/domains')
->desc('List Domains')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'listDomains')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1465,12 +1359,13 @@ App::get('/v1/projects/:projectId/domains')
]), Response::MODEL_DOMAIN_LIST);
});
App::get('/v1/projects/:projectId/domains/:domainId')
App::get('/v1/project/:projectId/domains/:domainId')
->desc('Get Domain')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->groups(['api', 'project'])
->label('scope', 'project.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'getDomain')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1499,12 +1394,12 @@ App::get('/v1/projects/:projectId/domains/:domainId')
$response->dynamic($domain, Response::MODEL_DOMAIN);
});
App::patch('/v1/projects/:projectId/domains/:domainId/verification')
App::patch('/v1/project/:projectId/domains/:domainId/verification')
->desc('Update Domain Verification Status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateDomainVerification')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
@@ -1559,12 +1454,12 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
$response->dynamic($domain, Response::MODEL_DOMAIN);
});
App::delete('/v1/projects/:projectId/domains/:domainId')
App::delete('/v1/project/:projectId/domains/:domainId')
->desc('Delete Domain')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->groups(['api', 'project'])
->label('scope', 'project.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.namespace', 'project')
->label('sdk.method', 'deleteDomain')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
+5 -5
View File
@@ -63,7 +63,7 @@ App::post('/v1/storage/buckets')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true)
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
@@ -154,7 +154,7 @@ App::get('/v1/storage/buckets')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_BUCKET_LIST)
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -235,7 +235,7 @@ App::put('/v1/storage/buckets/:bucketId')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
@@ -348,7 +348,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->label('sdk.response.model', Response::MODEL_FILE)
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
->param('fileId', '', new CustomId(), 'File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('file', [], new File(), 'Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](/docs/storage#file-input).', skipValidation: true)
->param('file', [], new File(), 'Binary file.', false)
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](/docs/permissions).', true)
->inject('request')
->inject('response')
@@ -680,7 +680,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE_LIST)
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
+53 -157
View File
@@ -1,12 +1,10 @@
<?php
use Appwrite\Auth\Auth;
use Appwrite\Auth\Validator\Phone;
use Appwrite\Detector\Detector;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Mail;
use Appwrite\Event\Phone as EventPhone;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Email;
use Utopia\Validator\Host;
@@ -22,6 +20,7 @@ use Appwrite\Utopia\Response;
use MaxMind\Db\Reader;
use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -36,9 +35,10 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Locale\Locale;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\ArrayList;
use Utopia\Validator\WhiteList;
App::post('/v1/teams')
->desc('Create Team')
@@ -76,7 +76,6 @@ App::post('/v1/teams')
],
'name' => $name,
'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'prefs' => new \stdClass(),
'search' => implode(' ', [$teamId, $name]),
])));
@@ -135,7 +134,7 @@ App::get('/v1/teams')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM_LIST)
->label('sdk.offline.model', '/teams')
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -200,36 +199,8 @@ App::get('/v1/teams/:teamId')
$response->dynamic($team, Response::MODEL_TEAM);
});
App::get('/v1/teams/:teamId/prefs')
->desc('Get Team Preferences')
->groups(['api', 'teams'])
->label('scope', 'teams.read')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/teams/get-team-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->label('sdk.offline.model', '/teams/{teamId}/prefs')
->param('teamId', '', new UID(), 'Team ID.')
->inject('response')
->inject('dbForProject')
->action(function (string $teamId, Response $response, Database $dbForProject) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$prefs = $team->getAttribute('prefs', []);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::put('/v1/teams/:teamId')
->desc('Update Name')
->desc('Update Team')
->groups(['api', 'teams'])
->label('event', 'teams.[teamId].update')
->label('scope', 'teams.write')
@@ -237,8 +208,8 @@ App::put('/v1/teams/:teamId')
->label('audits.resource', 'team/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updateName')
->label('sdk.description', '/docs/references/teams/update-team-name.md')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/teams/update-team.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
@@ -246,11 +217,10 @@ App::put('/v1/teams/:teamId')
->label('sdk.offline.key', '{teamId}')
->param('teamId', '', new UID(), 'Team ID.')
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events) {
->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $events) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -258,55 +228,15 @@ App::put('/v1/teams/:teamId')
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$team
$team = $dbForProject->updateDocument('teams', $team->getId(), $team
->setAttribute('name', $name)
->setAttribute('search', implode(' ', [$teamId, $name]));
$team = $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $team) {
return $dbForProject->updateDocument('teams', $team->getId(), $team);
});
->setAttribute('search', implode(' ', [$teamId, $name])));
$events->setParam('teamId', $team->getId());
$response->dynamic($team, Response::MODEL_TEAM);
});
App::put('/v1/teams/:teamId/prefs')
->desc('Update Preferences')
->groups(['api', 'teams'])
->label('event', 'teams.[teamId].update.prefs')
->label('scope', 'teams.write')
->label('audits.event', 'team.update')
->label('audits.resource', 'team/{response.$id}')
->label('audits.userId', '{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/teams/update-team-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->label('sdk.offline.model', '/teams/{teamId}/prefs')
->param('teamId', '', new UID(), 'Team ID.')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $events) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$team = $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('prefs', $prefs));
$events->setParam('teamId', $team->getId());
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::delete('/v1/teams/:teamId')
->desc('Delete Team')
->groups(['api', 'teams'])
@@ -379,9 +309,7 @@ App::post('/v1/teams/:teamId/memberships')
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
->label('abuse-limit', 10)
->param('teamId', '', new UID(), 'Team ID.')
->param('email', '', new Email(), 'Email of the new team member.', true)
->param('userId', '', new UID(), 'ID of the user to be added to a team.', true)
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
->param('email', '', new Email(), 'Email of the new team member.')
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), '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). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
->param('url', '', fn($clients) => 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
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
@@ -391,13 +319,9 @@ App::post('/v1/teams/:teamId/memberships')
->inject('dbForProject')
->inject('locale')
->inject('mails')
->inject('messaging')
->inject('events')
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) {
->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Event $events) {
if (empty($userId) && empty($email) && empty($phone)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required');
}
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
$isAppUser = Auth::isAppUser(Authorization::getRoles());
@@ -412,31 +336,8 @@ App::post('/v1/teams/:teamId/memberships')
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
if (!empty($userId)) {
$invitee = $dbForProject->getDocument('users', $userId);
if ($invitee->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND, 'User with given userId doesn\'t exist.', 404);
}
if (!empty($email) && $invitee->getAttribute('email', '') !== $email) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and email doesn\'t match', 409);
}
if (!empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and phone doesn\'t match', 409);
}
$email = $invitee->getAttribute('email', '');
$phone = $invitee->getAttribute('phone', '');
$name = empty($name) ? $invitee->getAttribute('name', '') : $name;
} elseif (!empty($email)) {
$invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address
if (!empty($invitee) && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given email and phone doesn\'t match', 409);
}
} elseif (!empty($phone)) {
$invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]);
if (!empty($invitee) && !empty($email) && $invitee->getAttribute('email', '') !== $email) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409);
}
}
$invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address
if (empty($invitee)) { // Create new user if no user with same email found
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
@@ -459,8 +360,7 @@ App::post('/v1/teams/:teamId/memberships')
Permission::update(Role::user($userId)),
Permission::delete(Role::user($userId)),
],
'email' => empty($email) ? null : $email,
'phone' => empty($phone) ? null : $phone,
'email' => $email,
'emailVerification' => false,
'status' => true,
'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS),
@@ -532,50 +432,46 @@ App::post('/v1/teams/:teamId/memberships')
} catch (Duplicate $th) {
throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS);
}
}
$url = Template::parseURL($url);
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
$url = Template::unParseURL($url);
if (!empty($email)) {
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
$url = Template::parseURL($url);
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
$url = Template::unParseURL($url);
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
$body->setParam('{{owner}}', $user->getAttribute('name'));
$body->setParam('{{team}}', $team->getAttribute('name'));
if (!$isPrivilegedUser && !$isAppUser) { // No need of confirmation when in admin or app mode
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
$body
->setParam('{{subject}}', $subject)
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
->setParam('{{name}}', $user->getAttribute('name'))
->setParam('{{body}}', $locale->getText("emails.invitation.body"))
->setParam('{{redirect}}', $url)
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"))
->setParam('{{project}}', $projectName)
->setParam('{{direction}}', $locale->getText('settings.direction'))
->setParam('{{bg-body}}', '#f7f7f7')
->setParam('{{bg-content}}', '#ffffff')
->setParam('{{text-content}}', '#000000');
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
$body->setParam('{{owner}}', $user->getAttribute('name'));
$body->setParam('{{team}}', $team->getAttribute('name'));
$body = $body->render();
$body
->setParam('{{subject}}', $subject)
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
->setParam('{{name}}', $user->getAttribute('name'))
->setParam('{{body}}', $locale->getText("emails.invitation.body"))
->setParam('{{redirect}}', $url)
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"))
->setParam('{{project}}', $projectName)
->setParam('{{direction}}', $locale->getText('settings.direction'))
->setParam('{{bg-body}}', '#f7f7f7')
->setParam('{{bg-content}}', '#ffffff')
->setParam('{{text-content}}', '#000000');
$mails
->setSubject($subject)
->setBody($body)
->setFrom($from)
->setRecipient($invitee->getAttribute('email'))
->setName($invitee->getAttribute('name'))
->trigger()
;
} elseif (!empty($phone)) {
$messaging
->setRecipient($phone)
->setMessage($url)
->trigger();
}
$body = $body->render();
$mails
->setSubject($subject)
->setBody($body)
->setFrom($from)
->setRecipient($invitee->getAttribute('email'))
->setName($invitee->getAttribute('name'))
->trigger()
;
}
$events
@@ -607,7 +503,7 @@ App::get('/v1/teams/:teamId/memberships')
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
->label('sdk.offline.model', '/teams/{teamId}/memberships')
->param('teamId', '', new UID(), 'Team ID.')
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -1002,7 +898,7 @@ App::get('/v1/teams/:teamId/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('teamId', '', new UID(), 'Team ID.')
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
->inject('response')
->inject('dbForProject')
->inject('locale')
+28 -59
View File
@@ -34,14 +34,11 @@ use Utopia\Validator\Text;
use Utopia\Validator\Boolean;
use MaxMind\Db\Reader;
use Utopia\Validator\Integer;
use Appwrite\Auth\Validator\PasswordHistory;
use Appwrite\Auth\Validator\PasswordDictionary;
/** TODO: Remove function when we move to using utopia/platform */
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $events): Document
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Database $dbForProject, Event $events): Document
{
$hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
if (!empty($email)) {
$email = \strtolower($email);
@@ -52,7 +49,6 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
? ID::unique()
: ID::custom($userId);
$password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null;
$user = $dbForProject->createDocument('users', new Document([
'$id' => $userId,
'$permissions' => [
@@ -65,11 +61,10 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
'phone' => $phone,
'phoneVerification' => false,
'status' => true,
'password' => $password,
'passwordHistory' => is_null($password) && $passwordHistory === 0 ? [] : [$password],
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
'password' => (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null,
'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash,
'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash],
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
'registration' => DateTime::now(),
'reset' => false,
'name' => $name,
@@ -106,15 +101,13 @@ App::post('/v1/users')
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', null, new Email(), 'User email.', true)
->param('phone', null, new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'Plain text user password. Must be at least 8 chars.', true, ['project', 'passwordsDictionary'])
->param('password', null, new Password(), 'Plain text user password. Must be at least 8 chars.', true)
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $events);
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -141,11 +134,10 @@ App::post('/v1/users/bcrypt')
->param('password', '', new Password(), 'User password hashed using Bcrypt.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -172,11 +164,10 @@ App::post('/v1/users/md5')
->param('password', '', new Password(), 'User password hashed using MD5.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -203,11 +194,10 @@ App::post('/v1/users/argon2')
->param('password', '', new Password(), 'User password hashed using Argon2.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -235,17 +225,16 @@ App::post('/v1/users/sha')
->param('passwordVersion', '', new WhiteList(['sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']), "Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'", true)
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Database $dbForProject, Event $events) {
$options = '{}';
if (!empty($passwordVersion)) {
$options = '{"version":"' . $passwordVersion . '"}';
}
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -272,11 +261,10 @@ App::post('/v1/users/phpass')
->param('password', '', new Password(), 'User password hashed using PHPass.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -308,10 +296,9 @@ App::post('/v1/users/scrypt')
->param('passwordLength', 64, new Integer(), 'Optional hash length used to hash password.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordSalt, int $passwordCpu, int $passwordMemory, int $passwordParallel, int $passwordLength, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
->action(function (string $userId, string $email, string $password, string $passwordSalt, int $passwordCpu, int $passwordMemory, int $passwordParallel, int $passwordLength, string $name, Response $response, Database $dbForProject, Event $events) {
$options = [
'salt' => $passwordSalt,
'costCpu' => $passwordCpu,
@@ -320,7 +307,7 @@ App::post('/v1/users/scrypt')
'length' => $passwordLength
];
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -350,11 +337,10 @@ App::post('/v1/users/scrypt-modified')
->param('passwordSignerKey', '', new Text(128), 'Signer key used to hash password.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -373,7 +359,7 @@ App::get('/v1/users')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER_LIST)
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -457,7 +443,7 @@ App::get('/v1/users/:userId/prefs')
throw new Exception(Exception::USER_NOT_FOUND);
}
$prefs = $user->getAttribute('prefs', []);
$prefs = $user->getAttribute('prefs', new \stdClass());
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
@@ -557,7 +543,7 @@ App::get('/v1/users/:userId/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('userId', '', new UID(), 'User ID.')
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
->inject('response')
->inject('dbForProject')
->inject('locale')
@@ -793,12 +779,11 @@ App::patch('/v1/users/:userId/password')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('userId', '', new UID(), 'User ID.')
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->param('password', '', new Password(), 'New user password. Must be at least 8 chars.')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) {
->action(function (string $userId, string $password, Response $response, Database $dbForProject, Event $events) {
$user = $dbForProject->getDocument('users', $userId);
@@ -806,27 +791,11 @@ App::patch('/v1/users/:userId/password')
throw new Exception(Exception::USER_NOT_FOUND);
}
$newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
$historyLimit = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
$history = [];
if ($historyLimit > 0) {
$history = $user->getAttribute('passwordHistory', []);
$validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions'));
if (!$validator->isValid($password)) {
throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409);
}
$history[] = $newPassword;
array_slice($history, (count($history) - $historyLimit), $historyLimit);
}
$user
->setAttribute('password', $newPassword)
->setAttribute('passwordHistory', $history)
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS);
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now());
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
+3 -7
View File
@@ -233,7 +233,7 @@ App::init()
->addHeader('Server', 'Appwrite')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true')
@@ -384,7 +384,7 @@ App::options()
$response
->addHeader('Server', 'Appwrite')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
@@ -485,10 +485,6 @@ App::error()
$error->setType(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
break;
}
} elseif ($error instanceof Utopia\Database\Exception\Conflict) {
$error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, null, null, $error);
$code = $error->getCode();
$message = $error->getMessage();
}
/** Wrap all exceptions inside Appwrite\Extend\Exception */
@@ -594,7 +590,7 @@ App::get('/.well-known/acme-challenge')
$uriChunks = \explode('/', $request->getURI());
$token = $uriChunks[\count($uriChunks) - 1];
$validator = new Text(100, allowList: [
$validator = new Text(100, [
...Text::NUMBERS,
...Text::ALPHABET_LOWER,
...Text::ALPHABET_UPPER,
+1 -17
View File
@@ -15,7 +15,6 @@ use Utopia\Validator\Text;
use Utopia\Storage\Validator\File;
use Utopia\Validator\WhiteList;
use Utopia\Database\Helpers\ID;
use Utopia\Validator\Nullable;
App::get('/v1/mock/tests/foo')
->desc('Get Foo')
@@ -268,7 +267,7 @@ App::post('/v1/mock/tests/general/upload')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Integer(true), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Sample array param')
->param('file', [], new File(), 'Sample file param', skipValidation: true)
->param('file', [], new File(), 'Sample file param', false)
->inject('request')
->inject('response')
->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) {
@@ -429,21 +428,6 @@ App::get('/v1/mock/tests/general/empty')
$response->noContent();
});
App::post('/v1/mock/tests/general/nullable')
->desc('Nullable Test')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'nullable')
->label('sdk.description', 'Mock a nullable parameter.')
->label('sdk.mock', true)
->param('required', '', new Text(100), 'Sample string param')
->param('nullable', '', new Nullable(new Text(100)), 'Sample string param')
->param('optional', '', new Text(100), 'Sample string param', true)
->action(function (string $required, string $nullable, ?string $optional) {
});
/** Endpoint to test if required headers are sent from the SDK */
App::get('/v1/mock/tests/general/headers')
->desc('Get headers')
+2
View File
@@ -5,6 +5,7 @@ use Appwrite\Event\Audit;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Mail;
use Appwrite\Extend\Exception;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Usage\Stats;
@@ -15,6 +16,7 @@ use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Cache\Adapter\Filesystem;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
+3 -3
View File
@@ -165,14 +165,14 @@ App::post('/v1/runtimes')
->desc("Create a new runtime server")
->param('runtimeId', '', new Text(64), 'Unique runtime ID.')
->param('source', '', new Text(0), 'Path to source files.')
->param('destination', '', new Text(0, 0), 'Destination folder to store build files into.', true)
->param('destination', '', new Text(0), 'Destination folder to store build files into.', true)
->param('vars', [], new Assoc(), 'Environment Variables required for the build.')
->param('commands', [], new ArrayList(new Text(1024), 100), 'Commands required to build the container. Maximum of 100 commands are allowed, each 1024 characters long.')
->param('runtime', '', new Text(128), 'Runtime for the cloud function.')
->param('baseImage', '', new Text(128), 'Base image name of the runtime.')
->param('entrypoint', '', new Text(256), 'Entrypoint of the code file.', true)
->param('remove', false, new Boolean(), 'Remove a runtime after execution.')
->param('workdir', '', new Text(256, 0), 'Working directory.', true)
->param('workdir', '', new Text(256), 'Working directory.', true)
->inject('orchestrationPool')
->inject('activeRuntimes')
->inject('response')
@@ -459,7 +459,7 @@ App::post('/v1/execution')
->desc('Create an execution')
->param('runtimeId', '', new Text(64), 'The runtimeID to execute.')
->param('vars', [], new Assoc(), 'Environment variables required for the build.')
->param('data', '', new Text(8192, 0), 'Data to be forwarded to the function, this is user specified.', true)
->param('data', '', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.')
->inject('activeRuntimes')
->inject('response')
+2 -1
View File
@@ -92,6 +92,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
$collections = Config::getParam('collections', []);
try {
$redis->flushAll();
Console::success('[Setup] - Creating database: appwrite...');
$dbForConsole->create();
} catch (\Exception $e) {
@@ -295,7 +296,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$log->addExtra('line', $th->getLine());
$log->addExtra('trace', $th->getTraceAsString());
$log->addExtra('detailedTrace', $th->getTrace());
$log->addExtra('roles', Authorization::getRoles());
$log->addExtra('roles', Authorization::$roles);
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
$log->setAction($action);
+9 -46
View File
@@ -53,7 +53,7 @@ use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\DatetimeValidator;
use Utopia\Database\Validator\Structure;
use Utopia\Locale\Locale;
use Utopia\Messaging\Adapters\SMS\Mock;
@@ -86,7 +86,6 @@ const APP_MODE_ADMIN = 'admin';
const APP_PAGING_LIMIT = 12;
const APP_LIMIT_COUNT = 5000;
const APP_LIMIT_USERS = 10000;
const APP_LIMIT_USER_PASSWORD_HISTORY = 20;
const APP_LIMIT_USER_SESSIONS_MAX = 100;
const APP_LIMIT_USER_SESSIONS_DEFAULT = 10;
const APP_LIMIT_ANTIVIRUS = 20000000; //20MB
@@ -100,8 +99,8 @@ const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate pe
const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return in list API calls
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 503;
const APP_VERSION_STABLE = '1.3.1';
const APP_CACHE_BUSTER = 501;
const APP_VERSION_STABLE = '1.2.1';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
@@ -285,23 +284,12 @@ Database::addFilter(
return null;
},
function (mixed $value, Document $document, Database $database) {
$attributes = $database->find('attributes', [
Query::equal('collectionInternalId', [$document->getInternalId()]),
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
Query::limit($database->getLimitForAttributes()),
]);
foreach ($attributes as $attribute) {
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
$options = $attribute->getAttribute('options');
foreach ($options as $key => $value) {
$attribute->setAttribute($key, $value);
}
$attribute->removeAttribute('options');
}
}
return $attributes;
return $database
->find('attributes', [
Query::equal('collectionInternalId', [$document->getInternalId()]),
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
Query::limit($database->getLimitForAttributes()),
]);
}
);
@@ -619,12 +607,6 @@ $register->set('smtp', function () {
$register->set('geodb', function () {
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2023-01.mmdb');
});
$register->set('passwordsDictionary', function () {
$content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords');
$content = explode("\n", $content);
$content = array_flip($content);
return $content;
});
$register->set('db', function () {
// This is usually for our workers or CLI commands scope
$dbHost = App::getEnv('_APP_DB_HOST', '');
@@ -1045,11 +1027,6 @@ App::setResource('geodb', function ($register) {
return $register->get('geodb');
}, ['register']);
App::setResource('passwordsDictionary', function ($register) {
/** @var Utopia\Registry\Registry $register */
return $register->get('passwordsDictionary');
}, ['register']);
App::setResource('sms', function () {
$dsn = new DSN(App::getEnv('_APP_SMS_PROVIDER'));
$user = $dsn->getUser();
@@ -1166,17 +1143,3 @@ App::setResource('schema', function ($utopia, $dbForProject) {
$params,
);
}, ['utopia', 'dbForProject']);
App::setResource('requestTimestamp', function ($request) {
//TODO: Move this to the Request class itself
$timestampHeader = $request->getHeader('x-appwrite-timestamp');
$requestTimestamp = null;
if (!empty($timestampHeader)) {
try {
$requestTimestamp = new \DateTime($timestampHeader);
} catch (\Throwable $e) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid X-Appwrite-Timestamp header value');
}
}
return $requestTimestamp;
}, ['request']);
+1 -2
View File
@@ -85,11 +85,10 @@ $cli
try {
$migration
->setProject($project, $projectDB, $consoleDB)
->setPDO($register->get('db'))
->execute();
} catch (\Throwable $th) {
Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage());
throw $th;
Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage());
}
clearProjectsCache($redis, $project);
+1 -1
View File
@@ -33,7 +33,7 @@ $cli
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) {
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', 'latest'])) {
throw new Exception('Unknown version given');
}
+1 -1
View File
@@ -383,7 +383,7 @@ class CertificatesV1 extends Worker
$locale->setDefault('en');
}
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
$subject = \sprintf($locale->getText("emails.certificate.subject"), $domain);
$body->setParam('{{domain}}', $domain);
+7 -79
View File
@@ -1,13 +1,10 @@
<?php
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Resque\Worker;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
require_once __DIR__ . '/../init.php';
@@ -92,51 +89,16 @@ class DatabaseV1 extends Worker
$format = $attribute->getAttribute('format', '');
$formatOptions = $attribute->getAttribute('formatOptions', []);
$filters = $attribute->getAttribute('filters', []);
$options = $attribute->getAttribute('options', []);
$project = $dbForConsole->getDocument('projects', $projectId);
try {
switch ($type) {
case Database::VAR_RELATIONSHIP:
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
if ($relatedCollection->isEmpty()) {
throw new Exception('Collection not found');
}
if (
!$dbForProject->createRelationship(
collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
type: $options['relationType'],
twoWay: $options['twoWay'],
id: $key,
twoWayKey: $options['twoWayKey'],
onDelete: $options['onDelete'],
)
) {
throw new Exception('Failed to create Attribute');
}
if ($options['twoWay']) {
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'available'));
}
break;
default:
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
throw new Exception('Failed to create Attribute');
}
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
throw new Exception('Failed to create Attribute');
}
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
} catch (\Throwable $th) {
Console::error($th->getMessage());
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed'));
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'failed'));
}
} finally {
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
@@ -159,10 +121,6 @@ class DatabaseV1 extends Worker
);
}
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId());
}
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
}
@@ -171,7 +129,6 @@ class DatabaseV1 extends Worker
* @param Document $collection
* @param Document $attribute
* @param string $projectId
* @throws Throwable
*/
protected function deleteAttribute(Document $database, Document $collection, Document $attribute, string $projectId): void
{
@@ -186,43 +143,19 @@ class DatabaseV1 extends Worker
$collectionId = $collection->getId();
$key = $attribute->getAttribute('key', '');
$status = $attribute->getAttribute('status', '');
$type = $attribute->getAttribute('type', '');
$project = $dbForConsole->getDocument('projects', $projectId);
$options = $attribute->getAttribute('options', []);
$relatedAttribute = new Document();
$relatedCollection = new Document();
// possible states at this point:
// - available: should not land in queue; controller flips these to 'deleting'
// - processing: hasn't finished creating
// - deleting: was available, in deletion queue for first time
// - failed: attribute was never created
// - stuck: attribute was available but cannot be removed
try {
if ($status !== 'failed') {
if ($type === Database::VAR_RELATIONSHIP) {
if ($options['twoWay']) {
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
if ($relatedCollection->isEmpty()) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
}
if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck'));
throw new Exception('Failed to delete Relationship');
}
} elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
throw new Exception('Failed to delete Attribute');
}
if ($status !== 'failed' && !$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
throw new Exception('Failed to delete Attribute');
}
$dbForProject->deleteDocument('attributes', $attribute->getId());
if (!$relatedAttribute->isEmpty()) {
$dbForProject->deleteDocument('attributes', $relatedAttribute->getId());
}
} catch (\Throwable $th) {
Console::error($th->getMessage());
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'stuck'));
@@ -266,8 +199,8 @@ class DatabaseV1 extends Worker
// array_values wraps array_diff to reindex array keys
// when found attribute is removed from array
$attributes = \array_values(\array_diff($attributes, [$attributes[$found]]));
$lengths = \array_values(\array_diff($lengths, isset($lengths[$found]) ? [$lengths[$found]] : []));
$orders = \array_values(\array_diff($orders, isset($orders[$found]) ? [$orders[$found]] : []));
$lengths = \array_values(\array_diff($lengths, [$lengths[$found]]));
$orders = \array_values(\array_diff($orders, [$orders[$found]]));
if (empty($attributes)) {
$dbForProject->deleteDocument('indexes', $index->getId());
@@ -302,11 +235,6 @@ class DatabaseV1 extends Worker
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) {
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId());
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
}
}
/**
-36
View File
@@ -58,9 +58,6 @@ class DeletesV1 extends Worker
break;
case DELETE_TYPE_TEAMS:
$this->deleteMemberships($document, $project->getId());
if ($project->getId() === 'console') {
$this->deleteProjectsByTeam($document);
}
break;
case DELETE_TYPE_BUCKETS:
$this->deleteBucket($document, $project->getId());
@@ -206,21 +203,6 @@ class DeletesV1 extends Worker
$dbForProject = $this->getProjectDB($projectId);
$relationships = \array_filter(
$document->getAttribute('attributes'),
fn ($attribute) => $attribute['type'] === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
if (!$relationship['twoWay']) {
continue;
}
$relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']);
$dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']);
$dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId());
$dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId());
}
$dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId());
$this->deleteByGroup('attributes', [
@@ -266,24 +248,6 @@ class DeletesV1 extends Worker
], $this->getProjectDB($projectId));
}
/**
* @param \Utopia\Database\Document $document
* @return void
* @throws \Exception
*/
protected function deleteProjectsByTeam(Document $document): void
{
$dbForConsole = $this->getConsoleDB();
$projects = $dbForConsole->find('projects', [
Query::equal('teamInternalId', [$document->getInternalId()])
]);
foreach ($projects as $project) {
$this->deleteProject($project);
}
}
/**
* @param Document $document project document
* @throws Exception
+8 -8
View File
@@ -43,27 +43,27 @@
"ext-sockets": "*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.11.*",
"utopia-php/abuse": "0.24.*",
"utopia-php/abuse": "0.18.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.25.*",
"utopia-php/audit": "0.20.*",
"utopia-php/cache": "0.8.*",
"utopia-php/cli": "0.13.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.35.*",
"utopia-php/database": "0.30.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/domains": "1.1.*",
"utopia-php/framework": "0.28.*",
"utopia-php/framework": "0.26.*",
"utopia-php/image": "0.5.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*",
"utopia-php/messaging": "0.1.*",
"utopia-php/orchestration": "0.6.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.14.*",
"utopia-php/storage": "0.13.*",
"utopia-php/swoole": "0.5.*",
"utopia-php/websocket": "0.1.*",
"resque/php-resque": "1.3.6",
"matomo/device-detector": "6.0.*",
"matomo/device-detector": "6.0.0",
"dragonmantank/cron-expression": "3.3.1",
"influxdb/influxdb-php": "1.15.2",
"phpmailer/phpmailer": "6.6.0",
@@ -79,7 +79,7 @@
}
],
"require-dev": {
"appwrite/sdk-generator": "0.32.*",
"appwrite/sdk-generator": "0.29.*",
"ext-fileinfo": "*",
"phpunit/phpunit": "9.5.20",
"squizlabs/php_codesniffer": "^3.6",
Generated
+136 -227
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "87de4ea3130e576470a63b21628e30fb",
"content-hash": "ac80cafdd8c2c6deaec3dfe628084655",
"packages": [
{
"name": "adhocore/jwt",
@@ -693,16 +693,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "2.4.4",
"version": "2.4.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
"reference": "67c26b443f348a51926030c83481b85718457d3d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d",
"reference": "67c26b443f348a51926030c83481b85718457d3d",
"shasum": ""
},
"require": {
@@ -792,7 +792,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.4.4"
"source": "https://github.com/guzzle/psr7/tree/2.4.3"
},
"funding": [
{
@@ -808,7 +808,7 @@
"type": "tidelift"
}
],
"time": "2023-03-09T13:19:02+00:00"
"time": "2022-10-26T14:07:24+00:00"
},
{
"name": "influxdb/influxdb-php",
@@ -1000,16 +1000,16 @@
},
{
"name": "matomo/device-detector",
"version": "6.0.6",
"version": "6.0.0",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "ce5ef5e6776c16af306d38e20674973f072e05ed"
"reference": "7fc2af3af62bd69e6e3404d561e371a83c112be9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/ce5ef5e6776c16af306d38e20674973f072e05ed",
"reference": "ce5ef5e6776c16af306d38e20674973f072e05ed",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/7fc2af3af62bd69e6e3404d561e371a83c112be9",
"reference": "7fc2af3af62bd69e6e3404d561e371a83c112be9",
"shasum": ""
},
"require": {
@@ -1065,7 +1065,7 @@
"source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/"
},
"time": "2023-01-16T08:18:02+00:00"
"time": "2022-04-11T09:58:17+00:00"
},
{
"name": "mongodb/mongodb",
@@ -1265,21 +1265,21 @@
},
{
"name": "psr/http-client",
"version": "1.0.2",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0 || ^2.0"
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
@@ -1299,7 +1299,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
@@ -1311,27 +1311,27 @@
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/1.0.2"
"source": "https://github.com/php-fig/http-client/tree/master"
},
"time": "2023-04-10T20:12:12+00:00"
"time": "2020-06-29T06:28:15+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.2",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "e616d01114759c4c489f93b099585439f795fe35"
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"psr/http-message": "^1.0 || ^2.0"
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
@@ -1351,7 +1351,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
@@ -1366,31 +1366,31 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
"source": "https://github.com/php-fig/http-factory/tree/master"
},
"time": "2023-04-10T20:10:41+00:00"
"time": "2019-04-30T12:38:16+00:00"
},
{
"name": "psr/http-message",
"version": "1.1",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
"dev-master": "1.0.x-dev"
}
},
"autoload": {
@@ -1419,9 +1419,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/1.1"
"source": "https://github.com/php-fig/http-message/tree/master"
},
"time": "2023-04-04T09:50:52+00:00"
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
@@ -1658,16 +1658,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.2.1",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e"
"reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
"reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3",
"reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3",
"shasum": ""
},
"require": {
@@ -1705,7 +1705,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0"
},
"funding": [
{
@@ -1721,7 +1721,7 @@
"type": "tidelift"
}
],
"time": "2023-03-01T10:25:55+00:00"
"time": "2022-11-25T10:21:52+00:00"
},
{
"name": "symfony/polyfill-php80",
@@ -1808,28 +1808,29 @@
},
{
"name": "utopia-php/abuse",
"version": "0.24.0",
"version": "0.18.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c"
"reference": "8496401234f73a49f8c4259d3e89ab4a7c1f9ecf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/403641f16a53b81ac40b91111a86e5672da49e8c",
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/8496401234f73a49f8c4259d3e89ab4a7c1f9ecf",
"reference": "8496401234f73a49f8c4259d3e89ab4a7c1f9ecf",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.35.*"
"utopia-php/database": "0.30.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.4"
"phpstan/phpstan": "1.9.x-dev",
"phpunit/phpunit": "^9.4",
"vimeo/psalm": "4.0.1"
},
"type": "library",
"autoload": {
@@ -1851,9 +1852,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.24.0"
"source": "https://github.com/utopia-php/abuse/tree/0.18.0"
},
"time": "2023-04-11T05:31:55+00:00"
"time": "2023-02-14T09:56:04+00:00"
},
{
"name": "utopia-php/analytics",
@@ -1912,26 +1913,28 @@
},
{
"name": "utopia-php/audit",
"version": "0.25.0",
"version": "0.20.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31"
"reference": "3fce3f4ad3ea9dfcb39b79668abd76331412a5ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/3fce3f4ad3ea9dfcb39b79668abd76331412a5ed",
"reference": "3fce3f4ad3ea9dfcb39b79668abd76331412a5ed",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.35.*"
"utopia-php/database": "0.30.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.3"
"phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.0.1"
},
"type": "library",
"autoload": {
@@ -1953,9 +1956,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.25.0"
"source": "https://github.com/utopia-php/audit/tree/0.20.0"
},
"time": "2023-04-11T05:31:15+00:00"
"time": "2023-02-14T09:46:54+00:00"
},
{
"name": "utopia-php/cache",
@@ -2112,37 +2115,33 @@
},
{
"name": "utopia-php/database",
"version": "0.35.0",
"version": "0.30.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2"
"reference": "1cea72c1217357bf0747ae4f28ebef57e9dc0e65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"url": "https://api.github.com/repos/utopia-php/database/zipball/1cea72c1217357bf0747ae4f28ebef57e9dc0e65",
"reference": "1cea72c1217357bf0747ae4f28ebef57e9dc0e65",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/cache": "0.8.*",
"utopia-php/framework": "0.*.*",
"utopia-php/mongo": "0.2.*"
"utopia-php/mongo": "0.0.2"
},
"require-dev": {
"ext-mongodb": "*",
"ext-redis": "*",
"fakerphp/faker": "^1.14",
"laravel/pint": "1.4.*",
"mongodb/mongodb": "1.8.0",
"pcov/clobber": "^2.0",
"phpstan/phpstan": "1.10.*",
"phpunit/phpunit": "^9.4",
"rregeer/phpunit-coverage-check": "^0.3.1",
"swoole/ide-helper": "4.8.0",
"utopia-php/cli": "^0.14.0"
"utopia-php/cli": "^0.14.0",
"vimeo/psalm": "4.0.1"
},
"type": "library",
"autoload": {
@@ -2154,7 +2153,7 @@
"license": [
"MIT"
],
"description": "A simple library to manage application persistence using multiple database adapters",
"description": "A simple library to manage application persistency using multiple database adapters",
"keywords": [
"database",
"framework",
@@ -2164,9 +2163,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.35.0"
"source": "https://github.com/utopia-php/database/tree/0.30.1"
},
"time": "2023-04-11T04:02:22+00:00"
"time": "2023-02-14T06:25:03+00:00"
},
{
"name": "utopia-php/domains",
@@ -2224,16 +2223,16 @@
},
{
"name": "utopia-php/framework",
"version": "0.28.1",
"version": "0.26.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/framework.git",
"reference": "7f22c556fc5991e54e5811a68fb39809b21bda55"
"reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/7f22c556fc5991e54e5811a68fb39809b21bda55",
"reference": "7f22c556fc5991e54e5811a68fb39809b21bda55",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e",
"reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e",
"shasum": ""
},
"require": {
@@ -2262,9 +2261,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/framework/issues",
"source": "https://github.com/utopia-php/framework/tree/0.28.1"
"source": "https://github.com/utopia-php/framework/tree/0.26.0"
},
"time": "2023-03-02T08:16:01+00:00"
"time": "2023-01-13T08:14:43+00:00"
},
{
"name": "utopia-php/image",
@@ -2472,16 +2471,16 @@
},
{
"name": "utopia-php/mongo",
"version": "0.2.0",
"version": "0.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/mongo.git",
"reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09"
"reference": "62f9a9c0201af91b6d0dd4f0aa8a335ec9b56a1e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09",
"reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/62f9a9c0201af91b6d0dd4f0aa8a335ec9b56a1e",
"reference": "62f9a9c0201af91b6d0dd4f0aa8a335ec9b56a1e",
"shasum": ""
},
"require": {
@@ -2526,9 +2525,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/mongo/issues",
"source": "https://github.com/utopia-php/mongo/tree/0.2.0"
"source": "https://github.com/utopia-php/mongo/tree/0.0.2"
},
"time": "2023-03-22T10:44:29+00:00"
"time": "2022-11-08T11:58:46+00:00"
},
{
"name": "utopia-php/orchestration",
@@ -2692,30 +2691,26 @@
},
{
"name": "utopia-php/storage",
"version": "0.14.0",
"version": "0.13.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/storage.git",
"reference": "eda6651ac16884dc2a79ecb984ea591ba1ed498c"
"reference": "ad1c00f24ca56e73888acc2af3deee4919b1194b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/eda6651ac16884dc2a79ecb984ea591ba1ed498c",
"reference": "eda6651ac16884dc2a79ecb984ea591ba1ed498c",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/ad1c00f24ca56e73888acc2af3deee4919b1194b",
"reference": "ad1c00f24ca56e73888acc2af3deee4919b1194b",
"shasum": ""
},
"require": {
"ext-brotli": "*",
"ext-fileinfo": "*",
"ext-lz4": "*",
"ext-snappy": "*",
"ext-zlib": "*",
"ext-zstd": "*",
"php": ">=8.0",
"utopia-php/framework": "0.*.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.0.1"
},
@@ -2729,6 +2724,12 @@
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
}
],
"description": "A simple Storage library to manage application storage",
"keywords": [
"framework",
@@ -2739,9 +2740,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/storage/issues",
"source": "https://github.com/utopia-php/storage/tree/0.14.0"
"source": "https://github.com/utopia-php/storage/tree/0.13.2"
},
"time": "2023-03-15T00:16:34+00:00"
"time": "2022-12-20T11:11:35+00:00"
},
{
"name": "utopia-php/swoole",
@@ -3037,16 +3038,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.32.1",
"version": "0.29.4",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df"
"reference": "35ec927d1de1854bebe8894e16b1646c3fdd5567"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ba1d7afd57e3baef06c04ce6abc26f79310146df",
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/35ec927d1de1854bebe8894e16b1646c3fdd5567",
"reference": "35ec927d1de1854bebe8894e16b1646c3fdd5567",
"shasum": ""
},
"require": {
@@ -3082,52 +3083,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.32.1"
"source": "https://github.com/appwrite/sdk-generator/tree/0.29.4"
},
"time": "2023-04-12T04:43:07+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
},
"time": "2022-05-02T15:47:09+00:00"
"time": "2023-02-03T05:44:59+00:00"
},
{
"name": "doctrine/instantiator",
@@ -3325,16 +3283,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.11.1",
"version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
"shasum": ""
},
"require": {
@@ -3372,7 +3330,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
},
"funding": [
{
@@ -3380,20 +3338,20 @@
"type": "tidelift"
}
],
"time": "2023-03-08T13:26:56+00:00"
"time": "2022-03-03T13:19:32+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.15.4",
"version": "v4.15.3",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039",
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039",
"shasum": ""
},
"require": {
@@ -3434,9 +3392,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3"
},
"time": "2023-03-05T19:49:14+00:00"
"time": "2023-01-16T22:05:37+00:00"
},
{
"name": "phar-io/manifest",
@@ -3661,27 +3619,24 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.7.1",
"version": "1.6.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "dfc078e8af9c99210337325ff5aa152872c98714"
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714",
"reference": "dfc078e8af9c99210337325ff5aa152872c98714",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "*",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
@@ -3713,9 +3668,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2"
},
"time": "2023-03-27T19:02:04+00:00"
"time": "2022-10-14T12:47:21+00:00"
},
{
"name": "phpspec/prophecy",
@@ -3785,70 +3740,25 @@
},
"time": "2023-02-02T15:41:36+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.18.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.1"
},
"time": "2023-04-07T11:51:11+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.26",
"version": "9.2.24",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
"reference": "2cf940ebc6355a9d430462811b5aaa308b174bed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed",
"reference": "2cf940ebc6355a9d430462811b5aaa308b174bed",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.15",
"nikic/php-parser": "^4.14",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@@ -3863,8 +3773,8 @@
"phpunit/phpunit": "^9.3"
},
"suggest": {
"ext-pcov": "PHP extension that provides line coverage",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
"ext-pcov": "*",
"ext-xdebug": "*"
},
"type": "library",
"extra": {
@@ -3897,7 +3807,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24"
},
"funding": [
{
@@ -3905,7 +3815,7 @@
"type": "github"
}
],
"time": "2023-03-06T12:58:08+00:00"
"time": "2023-01-26T08:26:55+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -5217,16 +5127,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.7.2",
"version": "3.7.1",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
"reference": "1359e176e9307e906dc3d890bcc9603ff6d90619"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619",
"reference": "1359e176e9307e906dc3d890bcc9603ff6d90619",
"shasum": ""
},
"require": {
@@ -5262,15 +5172,14 @@
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards",
"static analysis"
"standards"
],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2023-02-22T23:07:41+00:00"
"time": "2022-06-18T07:21:10+00:00"
},
{
"name": "swoole/ide-helper",
+1 -1
View File
@@ -1,4 +1,4 @@
<?php
echo 'execute init_file success' . PHP_EOL;
Yasd\Api\setRemoteHost('host.docker.internal'); //Set your development machine's IP
Yasd\Api\setRemoteHost('127.0.0.1'); //Set your development machine's IP
+1 -2
View File
@@ -83,7 +83,6 @@ services:
- ./docs:/usr/src/code/docs
- ./public:/usr/src/code/public
- ./src:/usr/src/code/src
- ./dev:/usr/src/code/dev
depends_on:
- mariadb
- redis
@@ -344,6 +343,7 @@ services:
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
#- ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
depends_on:
- redis
- mariadb
@@ -473,7 +473,6 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
- ./dev:/usr/src/code/dev
- appwrite-functions:/storage/functions:rw
- appwrite-builds:/storage/builds:rw
- /tmp:/tmp:rw
@@ -1 +0,0 @@
appwrite console variables
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createAnonymousSession(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createEmailSession(
"email@example.com",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createJWT(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createMagicURLSession(
"[USER_ID]",
"email@example.com",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createOAuth2Session(
"amazon",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createPhoneSession(
"[USER_ID]",
"+12065550100"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createPhoneVerification(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createRecovery(
"email@example.com",
"https://example.com"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createVerification(
"https://example.com"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,23 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.create(
"[USER_ID]",
"email@example.com",
"",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.deleteSession(
"[SESSION_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.deleteSessions(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.getPrefs(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.getSession(
"[SESSION_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.get(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,20 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.listLogs(
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.listSessions(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateEmail(
"email@example.com",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateMagicURLSession(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateName(
"[NAME]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePassword(
"",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePhoneSession(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePhoneVerification(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePhone(
"+12065550100",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePrefs(
mapOf( "a" to "b" )
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,24 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateRecovery(
"[USER_ID]",
"[SECRET]",
"password",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateSession(
"[SESSION_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,18 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateStatus(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateVerification(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getBrowser(
"aa",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getCreditCard(
"amex",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getFavicon(
"https://example.com"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getFlag(
"af",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getImage(
"https://example.com",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,20 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getInitials(
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,21 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getQR(
"[TEXT]",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,24 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.createDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]",
mapOf( "a" to "b" ),
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,23 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.deleteDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,23 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.getDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);

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