Merge branch 'master' of https://github.com/appwrite/appwrite into feat-db-pools-eldad
This commit is contained in:
commit
7484656be3
2
.env
2
.env
|
@ -61,7 +61,7 @@ _APP_SMTP_PORT=1025
|
|||
_APP_SMTP_SECURE=
|
||||
_APP_SMTP_USERNAME=
|
||||
_APP_SMTP_PASSWORD=
|
||||
_APP_SMS_PROVIDER=sms://mock
|
||||
_APP_SMS_PROVIDER=sms://username:password@mock
|
||||
_APP_SMS_FROM=+123456789
|
||||
_APP_STORAGE_LIMIT=30000000
|
||||
_APP_STORAGE_PREVIEW_LIMIT=20000000
|
||||
|
|
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -21,6 +21,11 @@ Happy contributing!
|
|||
|
||||
(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)
|
||||
|
||||
### Have you added your change to the [Changelog](https://github.com/appwrite/appwrite/blob/master/CHANGES.md)?
|
||||
|
||||
(The CHANGES.md file tracks all the changes that make it to the `main` branch. Add your change to this file in the following format)
|
||||
- One line description of your PR [#pr_number](Link to your PR)
|
||||
|
||||
### Have you read the [Contributing Guidelines on issues](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md)?
|
||||
|
||||
(Write your answer here.)
|
||||
|
|
19
.github/workflows/tests.yml
vendored
19
.github/workflows/tests.yml
vendored
|
@ -4,7 +4,7 @@ on: [pull_request]
|
|||
jobs:
|
||||
tests:
|
||||
name: Unit & E2E
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
@ -23,12 +23,14 @@ jobs:
|
|||
# Upstream bug causes buildkit pulls to fail so prefetch base images
|
||||
# https://github.com/moby/moby/issues/41864
|
||||
run: |
|
||||
echo "_APP_FUNCTIONS_RUNTIMES=php-8.0" >> .env
|
||||
export COMPOSE_INTERACTIVE_NO_CLI
|
||||
export DOCKER_BUILDKIT=1
|
||||
export COMPOSE_DOCKER_CLI_BUILD=1
|
||||
export BUILDKIT_PROGRESS=plain
|
||||
docker pull composer:2.0
|
||||
docker pull php:8.0-cli-alpine
|
||||
docker compose build --progress=plain
|
||||
docker compose build appwrite
|
||||
docker compose up -d
|
||||
sleep 10
|
||||
sleep 30
|
||||
- name: Doctor
|
||||
run: docker compose exec -T appwrite doctor
|
||||
|
||||
|
@ -37,10 +39,3 @@ jobs:
|
|||
|
||||
- name: Run Tests
|
||||
run: docker compose exec -T appwrite test --debug
|
||||
|
||||
- name: Teardown
|
||||
if: always()
|
||||
run: |
|
||||
docker ps -aq | xargs docker rm --force || true
|
||||
docker volume prune --force || true
|
||||
docker network prune --force || true
|
24
CHANGES.md
24
CHANGES.md
|
@ -1,6 +1,28 @@
|
|||
# Version 1.1.0
|
||||
|
||||
## Bugs
|
||||
- Fix license detection for Flutter and Dart SDKs [#4435](https://github.com/appwrite/appwrite/pull/4435)
|
||||
|
||||
# Version 1.0.3
|
||||
## Bugs
|
||||
- Fix document audit deletion [#4429](https://github.com/appwrite/appwrite/pull/4429)
|
||||
- Fix attribute and index deletion when deleting a collection [#4429](https://github.com/appwrite/appwrite/pull/4429)
|
||||
|
||||
# Version 1.0.2
|
||||
## Bugs
|
||||
- Fixed nullable values in functions variables [#3885](https://github.com/appwrite/appwrite/pull/3885)
|
||||
- Fixed migration for audit by migrating the `time` attribute [#4038](https://github.com/appwrite/appwrite/pull/4038)
|
||||
- Fixed default value for creating Boolean Attribute [#4040](https://github.com/appwrite/appwrite/pull/4040)
|
||||
- Fixed phone authentication code to be hashed in the internal database [#3906](https://github.com/appwrite/appwrite/pull/3906)
|
||||
- Fixed `/v1/teams/:teamId/memberships/:membershipId` response [#3883](https://github.com/appwrite/appwrite/pull/3883)
|
||||
- Fixed removing variables when function is deleted [#3884](https://github.com/appwrite/appwrite/pull/3884)
|
||||
- Fixed scheduled function not being triggered [#3908](https://github.com/appwrite/appwrite/pull/3908)
|
||||
- Fixed Phone Provider configuration [#3862](https://github.com/appwrite/appwrite/pull/3883)
|
||||
- Fixed Queries with `0` values [utopia-php/database#194](https://github.com/utopia-php/database/pull/194)
|
||||
|
||||
# Version 1.0.1
|
||||
## Bugs
|
||||
- Fixed migration for abuse by migrating the `time` attribute [3839](https://github.com/appwrite/appwrite/pull/3839)
|
||||
- Fixed migration for abuse by migrating the `time` attribute [#3839](https://github.com/appwrite/appwrite/pull/3839)
|
||||
|
||||
# Version 1.0.0
|
||||
## BREAKING CHANGES
|
||||
|
|
|
@ -93,6 +93,7 @@ git clone git@github.com:[YOUR_FORK_HERE]/appwrite.git
|
|||
|
||||
cd appwrite
|
||||
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
|
|
19
README-CN.md
19
README-CN.md
|
@ -8,13 +8,16 @@
|
|||
<br />
|
||||
</p>
|
||||
|
||||
<!-- [![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=friendly&color=90a88b&style=flat-square)](https://hacktoberfest.appwrite.io) -->
|
||||
<!-- [![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite) -->
|
||||
|
||||
[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=friendly&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io)
|
||||
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github)
|
||||
[![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite)
|
||||
[![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite)
|
||||
[![Build Status](https://img.shields.io/github/workflow/status/appwrite/appwrite/Tests?label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions)
|
||||
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
|
||||
[![翻译](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md)
|
||||
[![周边商店](https://img.shields.io/badge/swag%20store-f02e65?style=flat-square)](https://store.appwrite.io)
|
||||
|
||||
<!-- [![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite) -->
|
||||
<!-- [![Translate](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md) -->
|
||||
<!-- [![Swag Store](https://img.shields.io/badge/swag%20store-f02e65?style=flat-square)](https://store.appwrite.io) -->
|
||||
|
||||
[English](README.md) | 简体中文
|
||||
|
||||
|
@ -59,7 +62,7 @@ docker run -it --rm \
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:1.0.1
|
||||
appwrite/appwrite:1.0.3
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
@ -71,7 +74,7 @@ docker run -it --rm ^
|
|||
--volume //var/run/docker.sock:/var/run/docker.sock ^
|
||||
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
|
||||
--entrypoint="install" ^
|
||||
appwrite/appwrite:1.0.1
|
||||
appwrite/appwrite:1.0.3
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
@ -81,7 +84,7 @@ docker run -it --rm ,
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock ,
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
|
||||
--entrypoint="install" ,
|
||||
appwrite/appwrite:1.0.1
|
||||
appwrite/appwrite:1.0.3
|
||||
```
|
||||
|
||||
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
|
||||
|
|
24
README.md
24
README.md
|
@ -11,15 +11,17 @@
|
|||
<br />
|
||||
</p>
|
||||
|
||||
<!-- [![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=friendly&color=90a88b&style=flat-square)](https://hacktoberfest.appwrite.io) -->
|
||||
|
||||
<!-- [![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite) -->
|
||||
|
||||
[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=ready&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io)
|
||||
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github)
|
||||
[![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite)
|
||||
[![Build Status](https://img.shields.io/github/workflow/status/appwrite/appwrite/Tests?label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions)
|
||||
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
|
||||
[![Translate](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md)
|
||||
[![Swag Store](https://img.shields.io/badge/swag%20store-f02e65?style=flat-square)](https://store.appwrite.io)
|
||||
|
||||
<!-- [![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite) -->
|
||||
<!-- [![Translate](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md) -->
|
||||
<!-- [![Swag Store](https://img.shields.io/badge/swag%20store-f02e65?style=flat-square)](https://store.appwrite.io) -->
|
||||
|
||||
English | [简体中文](README-CN.md)
|
||||
|
||||
|
@ -73,7 +75,7 @@ docker run -it --rm \
|
|||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:1.0.1
|
||||
appwrite/appwrite:1.0.3
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
@ -85,17 +87,17 @@ docker run -it --rm ^
|
|||
--volume //var/run/docker.sock:/var/run/docker.sock ^
|
||||
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
|
||||
--entrypoint="install" ^
|
||||
appwrite/appwrite:1.0.1
|
||||
appwrite/appwrite:1.0.3
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
||||
```powershell
|
||||
docker run -it --rm ,
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock ,
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
|
||||
--entrypoint="install" ,
|
||||
appwrite/appwrite:1.0.1
|
||||
docker run -it --rm `
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock `
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
|
||||
--entrypoint="install" `
|
||||
appwrite/appwrite:1.0.3
|
||||
```
|
||||
|
||||
Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after installation completes.
|
||||
|
|
|
@ -523,17 +523,6 @@ $collections = [
|
|||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('region'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('description'),
|
||||
'type' => Database::VAR_STRING,
|
||||
|
@ -3032,17 +3021,6 @@ $collections = [
|
|||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('region'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('value'),
|
||||
'type' => Database::VAR_INTEGER,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* List of publicly accessiable system events
|
||||
* List of publicly accessible system events
|
||||
*/
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'name' => 'Default',
|
||||
'default' => true,
|
||||
'disabled' => false,
|
||||
]
|
||||
];
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -2,7 +2,6 @@
|
|||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\SMS\Adapter\Mock;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Auth\Validator\Phone;
|
||||
use Appwrite\Detector\Detector;
|
||||
|
@ -928,7 +927,7 @@ App::post('/v1/account/sessions/phone')
|
|||
])));
|
||||
}
|
||||
|
||||
$secret = (App::getEnv('_APP_SMS_PROVIDER') === 'sms://mock') ? Mock::$digits : Auth::codeGenerator();
|
||||
$secret = Auth::codeGenerator();
|
||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_PHONE);
|
||||
|
||||
$token = new Document([
|
||||
|
@ -1416,7 +1415,7 @@ App::get('/v1/account/sessions/:sessionId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_SESSION)
|
||||
->param('sessionId', null, new UID(), 'Session ID. Use the string \'current\' to get the current device session.')
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to get the current device session.')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
|
@ -1694,7 +1693,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->label('abuse-limit', 100)
|
||||
->param('sessionId', null, new UID(), 'Session ID. Use the string \'current\' to delete the current device session.')
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to delete the current device session.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
|
@ -1767,7 +1766,7 @@ App::patch('/v1/account/sessions/:sessionId')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_SESSION)
|
||||
->label('abuse-limit', 10)
|
||||
->param('sessionId', null, new UID(), 'Session ID. Use the string \'current\' to update the current device session.')
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to update the current device session.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
|
@ -2256,7 +2255,7 @@ App::post('/v1/account/verification/phone')
|
|||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
$verificationSecret = Auth::tokenGenerator();
|
||||
$secret = (App::getEnv('_APP_SMS_PROVIDER') === 'sms://mock') ? Mock::$digits : Auth::codeGenerator();
|
||||
$secret = Auth::codeGenerator();
|
||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM);
|
||||
|
||||
$verification = new Document([
|
||||
|
|
|
@ -89,11 +89,11 @@ function createAttribute(string $databaseId, string $collectionId, Document $att
|
|||
}
|
||||
|
||||
// Must throw here since dbForProject->createAttribute is performed by db worker
|
||||
if ($required && $default) {
|
||||
if ($required && isset($default)) {
|
||||
throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for required attribute');
|
||||
}
|
||||
|
||||
if ($array && $default) {
|
||||
if ($array && isset($default)) {
|
||||
throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for array attributes');
|
||||
}
|
||||
|
||||
|
@ -1783,7 +1783,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('key', '', new Key(), 'Index Key.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -1856,7 +1856,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
->label('sdk.response.model', Response::MODEL_DOCUMENT)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true)
|
||||
->inject('response')
|
||||
|
@ -2074,8 +2074,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('documentId', null, new UID(), 'Document ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
|
@ -2137,7 +2137,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
|
|||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', null, new UID(), 'Document ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -2243,8 +2243,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', null, new UID(), 'Collection ID.')
|
||||
->param('documentId', null, new UID(), 'Document ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
|
||||
->inject('response')
|
||||
|
@ -2376,8 +2376,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('documentId', null, new UID(), 'Document ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
|
@ -2534,7 +2534,7 @@ App::get('/v1/databases/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
@ -2648,7 +2648,7 @@ App::get('/v1/databases/:databaseId/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
@ -2763,7 +2763,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
|
|
@ -71,8 +71,13 @@ App::post('/v1/functions')
|
|||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('user')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Event $eventsInstance) {
|
||||
->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) {
|
||||
|
||||
$cron = !empty($schedule) ? new CronExpression($schedule) : null;
|
||||
$next = !empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
|
||||
$functionId = ($functionId == 'unique()') ? ID::unique() : $functionId;
|
||||
$function = $dbForProject->createDocument('functions', new Document([
|
||||
|
@ -86,11 +91,22 @@ App::post('/v1/functions')
|
|||
'schedule' => $schedule,
|
||||
'scheduleUpdatedAt' => DateTime::now(),
|
||||
'schedulePrevious' => null,
|
||||
'scheduleNext' => null,
|
||||
'scheduleNext' => $next,
|
||||
'timeout' => $timeout,
|
||||
'search' => implode(' ', [$functionId, $name, $runtime])
|
||||
]));
|
||||
|
||||
if ($next) {
|
||||
// Async task reschedule
|
||||
$functionEvent = new Func();
|
||||
$functionEvent
|
||||
->setFunction($function)
|
||||
->setType('schedule')
|
||||
->setUser($user)
|
||||
->setProject($project)
|
||||
->schedule(new \DateTime($next));
|
||||
}
|
||||
|
||||
$eventsInstance->setParam('functionId', $function->getId());
|
||||
|
||||
$response
|
||||
|
@ -281,7 +297,7 @@ App::get('/v1/functions/:functionId/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
@ -384,7 +400,7 @@ App::get('/v1/functions/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
@ -442,11 +458,9 @@ App::put('/v1/functions/:functionId')
|
|||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$original = $function->getAttribute('schedule', '');
|
||||
$cron = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
$cron = !empty($schedule) ? new CronExpression($schedule) : null;
|
||||
$next = !empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
|
||||
$scheduleUpdatedAt = $schedule !== $original ? DateTime::now() : $function->getAttribute('scheduleUpdatedAt');
|
||||
$enabled ??= $function->getAttribute('enabled', true);
|
||||
|
||||
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
|
@ -454,14 +468,14 @@ App::put('/v1/functions/:functionId')
|
|||
'name' => $name,
|
||||
'events' => $events,
|
||||
'schedule' => $schedule,
|
||||
'scheduleUpdatedAt' => $scheduleUpdatedAt,
|
||||
'scheduleUpdatedAt' => DateTime::now(),
|
||||
'scheduleNext' => $next,
|
||||
'timeout' => $timeout,
|
||||
'enabled' => $enabled,
|
||||
'search' => implode(' ', [$functionId, $name, $function->getAttribute('runtime')]),
|
||||
])));
|
||||
|
||||
if ($next && $schedule !== $original) {
|
||||
if ($next) {
|
||||
// Async task reschedule
|
||||
$functionEvent = new Func();
|
||||
$functionEvent
|
||||
|
@ -519,24 +533,10 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
throw new Exception(Exception::BUILD_NOT_READY);
|
||||
}
|
||||
|
||||
$schedule = $function->getAttribute('schedule', '');
|
||||
$cron = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
|
||||
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
'deployment' => $deployment->getId(),
|
||||
'scheduleNext' => $next,
|
||||
'deployment' => $deployment->getId()
|
||||
])));
|
||||
|
||||
if ($next) { // Init first schedule
|
||||
$functionEvent = new Func();
|
||||
$functionEvent
|
||||
->setType('schedule')
|
||||
->setFunction($function)
|
||||
->setProject($project)
|
||||
->schedule(new \DateTime($next));
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('deploymentId', $deployment->getId());
|
||||
|
@ -935,6 +935,67 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
$response->noContent();
|
||||
});
|
||||
|
||||
App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||
->groups(['api', 'functions'])
|
||||
->desc('Create Build')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.[functionId].deployments.[deploymentId].update')
|
||||
->label('audits.event', 'deployment.update')
|
||||
->label('audits.resource', 'function/{request.functionId}')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'createBuild')
|
||||
->label('sdk.description', '/docs/references/functions/create-build.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('deploymentId', '', new UID(), 'Deployment ID.')
|
||||
->param('buildId', '', new UID(), 'Build unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($deployment->isEmpty()) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $buildId));
|
||||
|
||||
if ($build->isEmpty()) {
|
||||
throw new Exception(Exception::BUILD_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($build->getAttribute('status') !== 'failed') {
|
||||
throw new Exception(Exception::BUILD_IN_PROGRESS, 'Build not failed');
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('deploymentId', $deployment->getId());
|
||||
|
||||
// Retry the build
|
||||
$buildEvent = new Build();
|
||||
$buildEvent
|
||||
->setType(BUILD_TYPE_RETRY)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
||||
|
||||
App::post('/v1/functions/:functionId/executions')
|
||||
->groups(['api', 'functions'])
|
||||
->desc('Create Execution')
|
||||
|
@ -1066,21 +1127,21 @@ App::post('/v1/functions/:functionId/executions')
|
|||
}
|
||||
|
||||
$vars = array_reduce($function['vars'] ?? [], function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value');
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? '';
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
$vars = \array_merge($vars, [
|
||||
'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
|
||||
'APPWRITE_FUNCTION_TRIGGER' => 'http',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
'APPWRITE_FUNCTION_DATA' => $data,
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
|
||||
'APPWRITE_FUNCTION_USER_ID' => $user->getId(),
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
'APPWRITE_FUNCTION_TRIGGER' => 'http',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' => $data ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => $user->getId() ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt ?? '',
|
||||
]);
|
||||
|
||||
/** Execute function */
|
||||
|
@ -1258,65 +1319,6 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
|||
$response->dynamic($execution, Response::MODEL_EXECUTION);
|
||||
});
|
||||
|
||||
App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||
->groups(['api', 'functions'])
|
||||
->desc('Retry Build')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.[functionId].deployments.[deploymentId].update')
|
||||
->label('audits.event', 'deployment.update')
|
||||
->label('audits.resource', 'function/{request.functionId}')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'retryBuild')
|
||||
->label('sdk.description', '/docs/references/functions/retry-build.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('deploymentId', '', new UID(), 'Deployment ID.')
|
||||
->param('buildId', '', new UID(), 'Build unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($deployment->isEmpty()) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $buildId));
|
||||
|
||||
if ($build->isEmpty()) {
|
||||
throw new Exception(Exception::BUILD_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($build->getAttribute('status') !== 'failed') {
|
||||
throw new Exception(Exception::BUILD_IN_PROGRESS, 'Build not failed');
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('deploymentId', $deployment->getId());
|
||||
|
||||
// Retry the build
|
||||
$buildEvent = new Build();
|
||||
$buildEvent
|
||||
->setType(BUILD_TYPE_RETRY)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
// Variables
|
||||
|
||||
App::post('/v1/functions/:functionId/variables')
|
||||
|
@ -1332,7 +1334,7 @@ App::post('/v1/functions/:functionId/variables')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VARIABLE)
|
||||
->param('functionId', null, new UID(), 'Function unique ID.', false)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
|
||||
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', false)
|
||||
->inject('response')
|
||||
|
@ -1384,7 +1386,7 @@ App::get('/v1/functions/:functionId/variables')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VARIABLE_LIST)
|
||||
->param('functionId', null, new UID(), 'Function unique ID.', false)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, Response $response, Database $dbForProject) {
|
||||
|
@ -1411,8 +1413,8 @@ App::get('/v1/functions/:functionId/variables/:variableId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VARIABLE)
|
||||
->param('functionId', null, new UID(), 'Function unique ID.', false)
|
||||
->param('variableId', null, new UID(), 'Variable unique ID.', false)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $variableId, Response $response, Database $dbForProject) {
|
||||
|
@ -1447,8 +1449,8 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VARIABLE)
|
||||
->param('functionId', null, new UID(), 'Function unique ID.', false)
|
||||
->param('variableId', null, new UID(), 'Variable unique ID.', false)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
||||
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
|
||||
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', true)
|
||||
->inject('response')
|
||||
|
@ -1499,8 +1501,8 @@ App::delete('/v1/functions/:functionId/variables/:variableId')
|
|||
->label('sdk.description', '/docs/references/functions/delete-variable.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('functionId', null, new UID(), 'Function unique ID.', false)
|
||||
->param('variableId', null, new UID(), 'Variable unique ID.', false)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $variableId, Response $response, Database $dbForProject) {
|
||||
|
|
|
@ -60,7 +60,6 @@ App::post('/v1/projects')
|
|||
->param('projectId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('region', '', new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.')
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
->param('logo', '', new Text(1024), 'Project logo.', true)
|
||||
->param('url', '', new URL(), 'Project URL.', true)
|
||||
|
@ -107,7 +106,6 @@ App::post('/v1/projects')
|
|||
'name' => $name,
|
||||
'teamInternalId' => $team->getInternalId(),
|
||||
'teamId' => $team->getId(),
|
||||
'region' => $region,
|
||||
'description' => $description,
|
||||
'logo' => $logo,
|
||||
'url' => $url,
|
||||
|
@ -341,7 +339,7 @@ App::get('/v1/projects/:projectId/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
@ -595,7 +593,7 @@ App::post('/v1/projects/:projectId/webhooks')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_WEBHOOK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
|
||||
|
@ -683,8 +681,8 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_WEBHOOK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('webhookId', null, new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
@ -717,8 +715,8 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_WEBHOOK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('webhookId', null, new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
|
||||
|
@ -771,8 +769,8 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_WEBHOOK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('webhookId', null, new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
@ -809,8 +807,8 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
|
|||
->label('sdk.method', 'deleteWebhook')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('webhookId', null, new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
@ -849,7 +847,7 @@ App::post('/v1/projects/:projectId/keys')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_KEY)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.')
|
||||
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
|
||||
|
@ -899,7 +897,7 @@ App::get('/v1/projects/:projectId/keys')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_KEY_LIST)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
@ -931,8 +929,8 @@ App::get('/v1/projects/:projectId/keys/:keyId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_KEY)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('keyId', null, new UID(), 'Key unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
|
||||
|
@ -965,8 +963,8 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_KEY)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('keyId', null, new UID(), 'Key unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
|
||||
|
@ -1011,8 +1009,8 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
|||
->label('sdk.method', 'deleteKey')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('keyId', null, new UID(), 'Key unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
|
||||
|
@ -1051,7 +1049,7 @@ App::post('/v1/projects/:projectId/platforms')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PLATFORM)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', null, new WhiteList([Origin::CLIENT_TYPE_WEB, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_LINUX, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_APPLE_IOS, Origin::CLIENT_TYPE_APPLE_MACOS, Origin::CLIENT_TYPE_APPLE_WATCHOS, Origin::CLIENT_TYPE_APPLE_TVOS, Origin::CLIENT_TYPE_ANDROID, Origin::CLIENT_TYPE_UNITY], true), 'Platform type.')
|
||||
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
|
||||
->param('key', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true)
|
||||
|
@ -1133,8 +1131,8 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PLATFORM)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('platformId', null, new UID(), 'Platform unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
|
||||
|
@ -1167,8 +1165,8 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PLATFORM)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('platformId', null, new UID(), 'Platform unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
|
||||
->param('key', '', new Text(256), 'Package name for android or bundle ID for iOS. Max length: 256 chars.', true)
|
||||
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
|
||||
|
@ -1214,8 +1212,8 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
|
|||
->label('sdk.method', 'deletePlatform')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('platformId', null, new UID(), 'Platform unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
|
||||
|
@ -1254,7 +1252,7 @@ App::post('/v1/projects/:projectId/domains')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOMAIN)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('domain', null, new DomainValidator(), 'Domain name.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
|
@ -1351,8 +1349,8 @@ App::get('/v1/projects/:projectId/domains/:domainId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOMAIN)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('domainId', null, new UID(), 'Domain unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('domainId', '', new UID(), 'Domain unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
|
@ -1385,8 +1383,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOMAIN)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('domainId', null, new UID(), 'Domain unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('domainId', '', new UID(), 'Domain unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
|
@ -1444,8 +1442,8 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
|
|||
->label('sdk.method', 'deleteDomain')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('domainId', null, new UID(), 'Domain unique ID.')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('domainId', '', new UID(), 'Domain unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->inject('deletes')
|
||||
|
|
|
@ -346,7 +346,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('file', [], new File(), 'Binary file.', false)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true)
|
||||
|
@ -667,7 +667,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE_LIST)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
|
@ -744,7 +744,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -793,7 +793,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE)
|
||||
->label('sdk.methodType', 'location')
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID')
|
||||
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
|
||||
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
|
||||
|
@ -959,7 +959,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', '*/*')
|
||||
->label('sdk.methodType', 'location')
|
||||
->param('bucketId', null, new UID(), 'Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
|
@ -1099,7 +1099,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', '*/*')
|
||||
->label('sdk.methodType', 'location')
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
|
@ -1256,7 +1256,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File unique ID.')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission string. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
|
||||
->inject('response')
|
||||
|
@ -1358,7 +1358,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->label('sdk.description', '/docs/references/storage/delete-file.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -1518,7 +1518,7 @@ App::get('/v1/storage/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
@ -1629,7 +1629,7 @@ App::get('/v1/storage/:bucketId/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
|
|
@ -553,7 +553,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
|||
->label('sdk.description', '/docs/references/teams/get-team-member.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->inject('response')
|
||||
|
@ -865,7 +865,7 @@ App::get('/v1/teams/:teamId/logs')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
->param('teamId', null, new UID(), 'Team ID.')
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
|
|
@ -290,10 +290,10 @@ App::post('/v1/users/scrypt')
|
|||
->param('email', '', new Email(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using Scrypt.')
|
||||
->param('passwordSalt', '', new Text(128), 'Optional salt used to hash password.')
|
||||
->param('passwordCpu', '', new Integer(), 'Optional CPU cost used to hash password.')
|
||||
->param('passwordMemory', '', new Integer(), 'Optional memory cost used to hash password.')
|
||||
->param('passwordParallel', '', new Integer(), 'Optional parallelization cost used to hash password.')
|
||||
->param('passwordLength', '', new Integer(), 'Optional hash length used to hash password.')
|
||||
->param('passwordCpu', 8, new Integer(), 'Optional CPU cost used to hash password.')
|
||||
->param('passwordMemory', 14, new Integer(), 'Optional memory cost used to hash password.')
|
||||
->param('passwordParallel', 1, new Integer(), 'Optional parallelization cost used to hash password.')
|
||||
->param('passwordLength', 64, new Integer(), 'Optional hash length used to hash password.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -888,7 +888,7 @@ App::patch('/v1/users/:userId/phone')
|
|||
try {
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$events->setParam('userId', $user->getId());
|
||||
|
@ -981,7 +981,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('sessionId', null, new UID(), 'Session ID.')
|
||||
->param('sessionId', '', new UID(), 'Session ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
|
@ -1176,7 +1176,7 @@ App::get('/v1/users/usage')
|
|||
};
|
||||
$stats[$metric][] = [
|
||||
'value' => 0,
|
||||
'date' => DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff),
|
||||
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
||||
];
|
||||
$backfill--;
|
||||
}
|
||||
|
|
|
@ -28,10 +28,6 @@ App::shutdown()
|
|||
$header = new View(__DIR__ . '/../../views/console/comps/header.phtml');
|
||||
$footer = new View(__DIR__ . '/../../views/console/comps/footer.phtml');
|
||||
|
||||
$header
|
||||
->setParam('regions', Config::getParam('regions', []))
|
||||
;
|
||||
|
||||
$footer
|
||||
->setParam('home', App::getEnv('_APP_HOME', ''))
|
||||
->setParam('version', App::getEnv('_APP_VERSION', 'UNKNOWN'))
|
||||
|
|
|
@ -28,6 +28,7 @@ $http = new Server("0.0.0.0", App::getEnv('PORT', 80));
|
|||
|
||||
$payloadSize = 6 * (1024 * 1024); // 6MB
|
||||
$workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6));
|
||||
|
||||
$http
|
||||
->set([
|
||||
'worker_num' => $workerNumber,
|
||||
|
|
|
@ -96,8 +96,8 @@ const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate
|
|||
const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate period in seconds
|
||||
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_BUSTER = 500;
|
||||
const APP_VERSION_STABLE = '1.0.1';
|
||||
const APP_CACHE_BUSTER = 501;
|
||||
const APP_VERSION_STABLE = '1.0.3';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
|
@ -190,7 +190,6 @@ Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes
|
|||
Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__ . '/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables
|
||||
Config::load('regions', __DIR__ . '/config/regions.php'); // List of available regions
|
||||
Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php');
|
||||
|
@ -1130,7 +1129,7 @@ App::setResource('sms', function () {
|
|||
$secret = $dsn->getPassword();
|
||||
|
||||
return match ($dsn->getHost()) {
|
||||
'mock' => new Mock('', ''), // used for tests
|
||||
'mock' => new Mock($user, $secret), // used for tests
|
||||
'twilio' => new Twilio($user, $secret),
|
||||
'text-magic' => new TextMagic($user, $secret),
|
||||
'telesign' => new Telesign($user, $secret),
|
||||
|
|
|
@ -72,7 +72,7 @@ Redistribution and use in source and binary forms, with or without modification,
|
|||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name Appwrite nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.';
|
||||
|
||||
|
|
|
@ -82,8 +82,7 @@ $logError = function (Throwable $error, string $action = 'syncUsageStats') use (
|
|||
function aggregateTimeseries(UtopiaDatabase $database, InfluxDatabase $influxDB, callable $logError): void
|
||||
{
|
||||
$interval = (int) App::getEnv('_APP_USAGE_TIMESERIES_INTERVAL', '30'); // 30 seconds (by default)
|
||||
$region = App::getEnv('region', 'default');
|
||||
$usage = new TimeSeries($region, $database, $influxDB, $logError);
|
||||
$usage = new TimeSeries($database, $influxDB, $logError);
|
||||
|
||||
Console::loop(function () use ($interval, $usage) {
|
||||
$now = date('d-m-Y H:i:s', time());
|
||||
|
@ -101,9 +100,8 @@ function aggregateTimeseries(UtopiaDatabase $database, InfluxDatabase $influxDB,
|
|||
function aggregateDatabase(UtopiaDatabase $database, callable $logError): void
|
||||
{
|
||||
$interval = (int) App::getEnv('_APP_USAGE_DATABASE_INTERVAL', '900'); // 15 minutes (by default)
|
||||
$region = App::getEnv('region', 'default');
|
||||
$usage = new Database($region, $database, $logError);
|
||||
$aggregrator = new Aggregator($region, $database, $logError);
|
||||
$usage = new Database($database, $logError);
|
||||
$aggregrator = new Aggregator($database, $logError);
|
||||
|
||||
Console::loop(function () use ($interval, $usage, $aggregrator) {
|
||||
$now = date('d-m-Y H:i:s', time());
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
<?php
|
||||
$regions = $this->getParam('regions', []);
|
||||
?>
|
||||
<header class="clear" data-version>
|
||||
<a href="/console" class="logo pull-start">
|
||||
<img src="/images/appwrite.svg" alt="Appwrite Light Logo" class="force-light" loading="lazy" />
|
||||
|
@ -218,18 +215,7 @@ $regions = $this->getParam('regions', []);
|
|||
name="projectId" />
|
||||
|
||||
<label>Name</label>
|
||||
<input type="text" class="full-width" name="name" required autocomplete="off" maxlength="128" />
|
||||
|
||||
<?php if(count($regions) > 1): ?>
|
||||
<label>Region</label>
|
||||
<select name="region" class="margin-bottom-xl">
|
||||
<?php foreach($regions as $key => $region): ?>
|
||||
<option <?php echo ($region['default'] ?? false) ? 'selected' : '' ?> <?php echo ($region['disabled'] ?? false ) ? 'disabled' : '' ?> value="<?php echo $key ?>"><?php echo $region['name'] ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<input type="hidden" name="region" value="<?php echo array_key_first($regions) ?>" class="margin-bottom-xl" />
|
||||
<?php endif; ?>
|
||||
<input type="text" class="full-width margin-bottom-xl" name="name" required autocomplete="off" maxlength="128" />
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
|
|
|
@ -81,6 +81,8 @@ $escapedPermissions = \array_map(function ($perm) {
|
|||
list="types"
|
||||
type="text"
|
||||
x-model="permission.role"
|
||||
@keydown.enter="prevent($event)"
|
||||
@keydown="clearPermission(index)"
|
||||
@keyup="updatePermission(index)"/>
|
||||
</td>
|
||||
<?php foreach ($escapedPermissions as $permission): ?>
|
||||
|
|
|
@ -391,9 +391,9 @@ sort($patterns);
|
|||
<tr>
|
||||
<th width="30"></th>
|
||||
<th width="160">Created</th>
|
||||
<th width="150">Status</th>
|
||||
<th width="120">Trigger</th>
|
||||
<th width="80">Runtime</th>
|
||||
<th width="100">Status</th>
|
||||
<th width="80">Trigger</th>
|
||||
<th width="60">Runtime</th>
|
||||
<th width=""></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -422,11 +422,11 @@ sort($patterns);
|
|||
<td data-title="">
|
||||
<div data-ls-if="{{execution.status}} === 'completed' || {{execution.status}} === 'failed'" data-title="" style="display: flex;">
|
||||
<button class="desktops-only pull-end link margin-start text-danger" data-ls-ui-trigger="execution-stderr-{{execution.$id}}">Stderr</button>
|
||||
<!--button class="desktops-only pull-end link margin-start" data-ls-ui-trigger="execution-stdout-{{execution.$id}}">Stdout</button-->
|
||||
<button class="desktops-only pull-end link margin-start" data-ls-ui-trigger="execution-stdout-{{execution.$id}}">Stdout</button>
|
||||
<button class="desktops-only pull-end link margin-start" data-ls-ui-trigger="execution-response-{{execution.$id}}">Response</button>
|
||||
|
||||
<button class="phones-only-inline tablets-only-inline link margin-end-small" data-ls-ui-trigger="execution-response-{{execution.$id}}">Response</button>
|
||||
<!--button class="phones-only-inline tablets-only-inline link margin-end-small" data-ls-ui-trigger="execution-stdout-{{execution.$id}}">Stdout</button-->
|
||||
<button class="phones-only-inline tablets-only-inline link margin-end-small" data-ls-ui-trigger="execution-stdout-{{execution.$id}}">Stdout</button>
|
||||
<button class="phones-only-inline tablets-only-inline link text-danger" data-ls-ui-trigger="execution-stderr-{{execution.$id}}">Stderr</button>
|
||||
|
||||
<div data-ui-modal class="modal width-large box close" data-button-alias="none" data-open-event="execution-response-{{execution.$id}}">
|
||||
|
@ -841,6 +841,8 @@ sort($patterns);
|
|||
data-failure-param-alert-text="Failed to execute function"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input name="async" data-cast-to="bool" value="true" type="hidden" />
|
||||
|
||||
<label for="execution-data">Custom Data</label>
|
||||
<textarea id="execution-data" name="data" autocomplete="off" class="margin-bottom" placeholder="Data string (optional)"></textarea>
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ class BuildsV1 extends Worker
|
|||
|
||||
/** Trigger Webhook */
|
||||
$deploymentModel = new Deployment();
|
||||
|
||||
$deploymentUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME);
|
||||
$deploymentUpdate
|
||||
->setProject($project)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Network\Validator\CNAME;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\App;
|
||||
|
@ -374,19 +375,19 @@ class CertificatesV1 extends Worker
|
|||
Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage);
|
||||
|
||||
// Send mail to administratore mail
|
||||
Resque::enqueue(Event::MAILS_QUEUE_NAME, Event::MAILS_CLASS_NAME, [
|
||||
'from' => 'console',
|
||||
'project' => 'console',
|
||||
'name' => 'Appwrite Administrator',
|
||||
'recipient' => App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS'),
|
||||
'url' => 'https://' . $domain,
|
||||
'locale' => App::getEnv('_APP_LOCALE', 'en'),
|
||||
'type' => MAIL_TYPE_CERTIFICATE,
|
||||
|
||||
'domain' => $domain,
|
||||
'error' => $errorMessage,
|
||||
'attempt' => $attempt
|
||||
]);
|
||||
$mail = new Mail();
|
||||
$mail
|
||||
->setType(MAIL_TYPE_CERTIFICATE)
|
||||
->setRecipient(App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS'))
|
||||
->setUrl('https://' . $domain)
|
||||
->setLocale(App::getEnv('_APP_LOCALE', 'en'))
|
||||
->setName('Appwrite Administrator')
|
||||
->setPayload([
|
||||
'domain' => $domain,
|
||||
'error' => $errorMessage,
|
||||
'attempt' => $attempt
|
||||
])
|
||||
->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -195,21 +195,24 @@ class DeletesV1 extends Worker
|
|||
protected function deleteCollection(Document $document, Document $project): void
|
||||
{
|
||||
$collectionId = $document->getId();
|
||||
$databaseId = str_replace('database_', '', $document->getCollection());
|
||||
$databaseId = $document->getAttribute('databaseId');
|
||||
$databaseInternalId = $document->getAttribute('databaseInternalId');
|
||||
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
|
||||
$dbForProject->deleteCollection('database_' . $databaseId . '_collection_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId());
|
||||
|
||||
$this->deleteByGroup('attributes', [
|
||||
Query::equal('databaseId', [$databaseId]),
|
||||
Query::equal('collectionId', [$collectionId])
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteByGroup('indexes', [
|
||||
Query::equal('databaseId', [$databaseId]),
|
||||
Query::equal('collectionId', [$collectionId])
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteAuditLogsByResource('collection/' . $collectionId, $project);
|
||||
$this->deleteAuditLogsByResource('database/' . $databaseId . '/collection/' . $collectionId, $project);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,6 +418,14 @@ class DeletesV1 extends Worker
|
|||
$dbForProject = $this->getProjectDB($project);
|
||||
$functionId = $document->getId();
|
||||
|
||||
/**
|
||||
* Delete Variables
|
||||
*/
|
||||
Console::info("Deleting variables for function " . $functionId);
|
||||
$this->deleteByGroup('variables', [
|
||||
Query::equal('functionId', [$functionId])
|
||||
], $dbForProject);
|
||||
|
||||
/**
|
||||
* Delete Deployments
|
||||
*/
|
||||
|
|
|
@ -271,17 +271,17 @@ class FunctionsV1 extends Worker
|
|||
/** Collect environment variables */
|
||||
$vars = \array_merge($vars, [
|
||||
'APPWRITE_FUNCTION_ID' => $functionId,
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => $deploymentId,
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
|
||||
'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
|
||||
'APPWRITE_FUNCTION_DATA' => $data,
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
|
||||
'APPWRITE_FUNCTION_USER_ID' => $user->getId(),
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT' => $event ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => $eventData ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' => $data ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => $user->getId() ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt ?? '',
|
||||
]);
|
||||
|
||||
/** Execute function */
|
||||
|
|
|
@ -32,9 +32,10 @@ class MailsV1 extends Worker
|
|||
return;
|
||||
}
|
||||
|
||||
$project = new Document($this->args['project']);
|
||||
$project = new Document($this->args['project'] ?? []);
|
||||
$user = new Document($this->args['user'] ?? []);
|
||||
$team = new Document($this->args['team'] ?? []);
|
||||
$payload = $this->args['payload'] ?? [];
|
||||
|
||||
$recipient = $this->args['recipient'];
|
||||
$url = $this->args['url'];
|
||||
|
@ -42,20 +43,20 @@ class MailsV1 extends Worker
|
|||
$type = $this->args['type'];
|
||||
$prefix = $this->getPrefix($type);
|
||||
$locale = new Locale($this->args['locale']);
|
||||
$projectName = $project->getAttribute('name', '[APP-NAME]');
|
||||
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
|
||||
|
||||
if (!$this->doesLocaleExist($locale, $prefix)) {
|
||||
$locale->setDefault('en');
|
||||
}
|
||||
|
||||
$from = $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
|
||||
$subject = '';
|
||||
switch ($type) {
|
||||
case MAIL_TYPE_CERTIFICATE:
|
||||
$domain = $this->args['domain'];
|
||||
$error = $this->args['error'];
|
||||
$attempt = $this->args['attempt'];
|
||||
$domain = $payload['domain'];
|
||||
$error = $payload['error'];
|
||||
$attempt = $payload['attempt'];
|
||||
|
||||
$subject = \sprintf($locale->getText("$prefix.subject"), $domain);
|
||||
$body->setParam('{{domain}}', $domain);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Auth\SMS;
|
||||
use Appwrite\SMS\Adapter\Mock;
|
||||
use Appwrite\SMS\Adapter\Telesign;
|
||||
use Appwrite\SMS\Adapter\TextMagic;
|
||||
|
@ -9,6 +8,7 @@ use Appwrite\SMS\Adapter\Msg91;
|
|||
use Appwrite\SMS\Adapter\Vonage;
|
||||
use Appwrite\DSN\DSN;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Appwrite\SMS\Adapter;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
|
@ -19,7 +19,7 @@ Console::success(APP_NAME . ' messaging worker v1 has started' . "\n");
|
|||
|
||||
class MessagingV1 extends Worker
|
||||
{
|
||||
protected ?SMS $sms = null;
|
||||
protected ?Adapter $sms = null;
|
||||
protected ?string $from = null;
|
||||
|
||||
public function getName(): string
|
||||
|
@ -34,7 +34,7 @@ class MessagingV1 extends Worker
|
|||
$secret = $dsn->getPassword();
|
||||
|
||||
$this->sms = match ($dsn->getHost()) {
|
||||
'mock' => new Mock('', ''), // used for tests
|
||||
'mock' => new Mock($user, $secret), // used for tests
|
||||
'twilio' => new Twilio($user, $secret),
|
||||
'text-magic' => new TextMagic($user, $secret),
|
||||
'telesign' => new Telesign($user, $secret),
|
||||
|
|
|
@ -70,12 +70,13 @@ services:
|
|||
appwrite:
|
||||
container_name: appwrite
|
||||
<<: *x-logging
|
||||
image: appwrite-dev
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- DEBUG=false
|
||||
- TESTING=true
|
||||
- VERSION=dev
|
||||
DEBUG: false
|
||||
TESTING: true
|
||||
VERSION: dev
|
||||
ports:
|
||||
- 9501:80
|
||||
networks:
|
||||
|
@ -181,8 +182,8 @@ services:
|
|||
entrypoint: realtime
|
||||
<<: *x-logging
|
||||
container_name: appwrite-realtime
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 9505:80
|
||||
labels:
|
||||
|
@ -227,8 +228,7 @@ services:
|
|||
entrypoint: worker-audits
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-audits
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -255,8 +255,7 @@ services:
|
|||
entrypoint: worker-webhooks
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-webhooks
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -282,8 +281,7 @@ services:
|
|||
entrypoint: worker-deletes
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-deletes
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
|
@ -318,8 +316,7 @@ services:
|
|||
entrypoint: worker-databases
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-databases
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -347,8 +344,7 @@ services:
|
|||
entrypoint: worker-builds
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-builds
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -377,8 +373,7 @@ services:
|
|||
entrypoint: worker-certificates
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-certificates
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
|
@ -410,8 +405,7 @@ services:
|
|||
entrypoint: worker-functions
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-functions
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -444,12 +438,7 @@ services:
|
|||
<<: *x-logging
|
||||
entrypoint: executor
|
||||
stop_signal: SIGINT
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- DEBUG=false
|
||||
- TESTING=true
|
||||
- VERSION=dev
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
appwrite:
|
||||
runtimes:
|
||||
|
@ -489,8 +478,7 @@ services:
|
|||
entrypoint: worker-mails
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-mails
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -522,8 +510,7 @@ services:
|
|||
entrypoint: worker-messaging
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-messaging
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -547,8 +534,7 @@ services:
|
|||
entrypoint: maintenance
|
||||
<<: *x-logging
|
||||
container_name: appwrite-maintenance
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -581,10 +567,7 @@ services:
|
|||
- --type=timeseries
|
||||
<<: *x-logging
|
||||
container_name: appwrite-usage-timeseries
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- DEBUG=false
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -617,10 +600,7 @@ services:
|
|||
- --type=database
|
||||
<<: *x-logging
|
||||
container_name: appwrite-usage-database
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- DEBUG=false
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -651,8 +631,7 @@ services:
|
|||
entrypoint: schedule
|
||||
<<: *x-logging
|
||||
container_name: appwrite-schedule
|
||||
build:
|
||||
context: .
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
@ -749,7 +728,7 @@ services:
|
|||
# MailCatcher - An SMTP server. Catches all system emails and displays them in a nice UI.
|
||||
# RequestCatcher - An HTTP server. Catches all system https calls and displays them using a simple HTTP API. Used to debug & tests webhooks and HTTP tasks
|
||||
# RedisCommander - A nice UI for exploring Redis data
|
||||
# Resque - A nice UI for exploring Reddis pub/sub, view the different queues workloads, pending and failed tasks
|
||||
# Resque - A nice UI for exploring Redis pub/sub, view the different queues workloads, pending and failed tasks
|
||||
# Chronograf - A nice UI for exploring InfluxDB data
|
||||
# Webgrind - A nice UI for exploring and debugging code-level stuff
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
## 7.0.0-dev.2
|
||||
## 7.1.0
|
||||
|
||||
* Role helper update
|
||||
|
||||
## 7.0.0
|
||||
|
||||
### NEW
|
||||
* Support for Appwrite 1.0.0-RC1
|
||||
* Support for Appwrite 1.0.0
|
||||
* More verbose headers have been included in the Clients - `x-sdk-name`, `x-sdk-platform`, `x-sdk-language`, `x-sdk-version`
|
||||
* Helper classes and methods for Permissions, Roles and IDs
|
||||
* Helper methods to suport new queries
|
||||
|
@ -26,7 +31,7 @@
|
|||
3. `greater` renamed to `greaterThan`
|
||||
4. `greaterEqual` renamed to `greaterThanEqual`
|
||||
|
||||
**Full Changelog for Appwrite 1.0.0-RC1 can be found here**: https://github.com/appwrite/appwrite/blob/master/CHANGES.md
|
||||
**Full Changelog for Appwrite 1.0.0 can be found here**: https://github.com/appwrite/appwrite/blob/master/CHANGES.md
|
||||
|
||||
## 6.0.1
|
||||
* Dependency upgrades
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
## 8.0.0-dev.2 Latest
|
||||
## 8.1.0
|
||||
|
||||
* Role helper update
|
||||
|
||||
## 8.0.0
|
||||
|
||||
### NEW
|
||||
* Support for Appwrite 1.0.0-RC1
|
||||
* Support for Appwrite 1.0.0
|
||||
* More verbose headers have been included in the Clients - `x-sdk-name`, `x-sdk-platform`, `x-sdk-language`, `x-sdk-version`
|
||||
* Helper classes and methods for Permissions, Roles and IDs
|
||||
* Helper methods to suport new queries
|
||||
|
@ -21,7 +25,7 @@
|
|||
4. `greaterEqual` renamed to `greaterThanEqual`
|
||||
* `User` response model is now renamed to `Account`
|
||||
|
||||
**Full Changelog for Appwrite 1.0.0-RC1 can be found here**:
|
||||
**Full Changelog for Appwrite 1.0.0 can be found here**:
|
||||
https://github.com/appwrite/appwrite/blob/master/CHANGES.md
|
||||
|
||||
## 7.0.0
|
||||
|
|
|
@ -5,12 +5,12 @@ This document is part of the Appwrite contributors' guide. Before you continue r
|
|||
## Getting Started
|
||||
|
||||
### Agenda
|
||||
Adding new features may require various configurations options to be set by the users. And for such options, we use environment variables in Appwrite.
|
||||
Adding new features may require various configuration options to be set by the users. And for such options, we use environment variables in Appwrite.
|
||||
|
||||
This tutorial will cover how to properly add a new environment variable in Appwrite.
|
||||
|
||||
### Naming environment variable
|
||||
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the Redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally, a properly describing name is given to the variable. For example, `_APP_REDIS_HOST` is an environment variable for Redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
|
||||
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the Redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally, a properly describing name is given to the variable. For example, `_APP_REDIS_HOST` is an environment variable for the Redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
|
||||
|
||||
### Describe new environment variable
|
||||
First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variable description to create a new one so that you will not miss any required fields.
|
||||
|
|
|
@ -62,7 +62,7 @@ We maintain a [`locale branch`](https://github.com/appwrite/appwrite/tree/locale
|
|||
|
||||
2. **en.json**
|
||||
|
||||
[en.json]((https://github.com/appwrite/appwrite/blob/locale/app/config/locale/translations/en.json)) contains the English translation for all the terms that are present in **terms.json**. You can use this file as a reference when making a contribution for your language.
|
||||
[en.json](https://github.com/appwrite/appwrite/blob/locale/app/config/locale/translations/en.json) contains the English translation for all the terms that are present in **terms.json**. You can use this file as a reference when making a contribution for your language.
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
12
public/dist/scripts/app-all.js
vendored
12
public/dist/scripts/app-all.js
vendored
|
@ -519,14 +519,12 @@ class Projects extends Service{constructor(client){super(client);}
|
|||
list(queries,search){return __awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof queries!=='undefined'){payload['queries']=queries;}
|
||||
if(typeof search!=='undefined'){payload['search']=search;}
|
||||
const uri=new URL(this.client.config.endpoint+path);return yield this.client.call('get',uri,{'content-type':'application/json',},payload);});}
|
||||
create(projectId,name,teamId,region,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
create(projectId,name,teamId,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
if(typeof region==='undefined'){throw new AppwriteException('Missing required parameter: "region"');}
|
||||
let path='/projects';let payload={};if(typeof projectId!=='undefined'){payload['projectId']=projectId;}
|
||||
if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof teamId!=='undefined'){payload['teamId']=teamId;}
|
||||
if(typeof region!=='undefined'){payload['region']=region;}
|
||||
if(typeof description!=='undefined'){payload['description']=description;}
|
||||
if(typeof logo!=='undefined'){payload['logo']=logo;}
|
||||
if(typeof url!=='undefined'){payload['url']=url;}
|
||||
|
@ -539,11 +537,9 @@ if(typeof legalTaxId!=='undefined'){payload['legalTaxId']=legalTaxId;}
|
|||
const uri=new URL(this.client.config.endpoint+path);return yield this.client.call('post',uri,{'content-type':'application/json',},payload);});}
|
||||
get(projectId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.client.config.endpoint+path);return yield this.client.call('get',uri,{'content-type':'application/json',},payload);});}
|
||||
update(projectId,name,region,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
update(projectId,name,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof region==='undefined'){throw new AppwriteException('Missing required parameter: "region"');}
|
||||
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof region!=='undefined'){payload['region']=region;}
|
||||
if(typeof description!=='undefined'){payload['description']=description;}
|
||||
if(typeof logo!=='undefined'){payload['logo']=logo;}
|
||||
if(typeof url!=='undefined'){payload['url']=url;}
|
||||
|
@ -4017,7 +4013,7 @@ this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePer
|
|||
if(existing===undefined){let newPermission={role,create:false,read:false,update:false,xdelete:false,};newPermission[type]=true;this.permissions.push(newPermission);}
|
||||
if(index!==-1){existing[type]=true;this.permissions[index]=existing;}});},addPermission(formId){if(this.permissions.length>0&&!this.validate(formId,this.permissions.length-1)){return;}
|
||||
this.permissions.push({role:'',create:false,read:false,update:false,xdelete:false,});},updatePermission(index){setTimeout(()=>{const permission=this.permissions[index];Object.keys(permission).forEach(key=>{if(key==='role'){return;}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},clearPermission(index){let currentRole=this.permissions[index].role;this.rawPermissions=this.rawPermissions.filter(p=>{let{type,role}=this.parsePermission(p);return role!==currentRole;});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
return key;},parseOutputPermission(key){if(key==='xdelete'){return'delete';}
|
||||
return key;},validate(formId,index){const form=document.getElementById(formId);const input=document.getElementById(`${formId}Input${index}`);const permission=this.permissions[index];input.setCustomValidity('');if(permission.role===''){input.setCustomValidity('Role is required');}else if(!Object.entries(permission).some(([k,v])=>!k.includes('role')&&v)){input.setCustomValidity('No permissions selected');}else if(this.permissions.some(p=>p.role===permission.role&&p!==permission)){input.setCustomValidity('Role entry already exists');}
|
||||
return form.reportValidity();},prevent(event){event.preventDefault();event.stopPropagation();}}));});})(window);(function(window){"use strict";window.ls.view.add({selector:"data-service",controller:function(element,view,container,form,alerts,expression,window){let action=element.dataset["service"];let service=element.dataset["name"]||null;let event=expression.parse(element.dataset["event"]);let confirm=element.dataset["confirm"]||"";let loading=element.dataset["loading"]||"";let loaderId=null;let scope=element.dataset["scope"]||"sdk";let success=element.dataset["success"]||"";let failure=element.dataset["failure"]||"";let running=false;let callbacks={hide:function(){return function(){return element.style.opacity='0';};},reset:function(){return function(){if("FORM"===element.tagName){return element.reset();}
|
||||
|
@ -4149,7 +4145,7 @@ element.classList.add('scroll-to-bottom')}
|
|||
else{element.classList.remove('scroll-to-bottom')
|
||||
element.classList.add('scroll-to-top')}
|
||||
position=direction;let current=Math.ceil(direction/window.innerHeight);element.setAttribute('data-views-total',Math.ceil(element.scrollHeight/window.innerHeight));element.setAttribute('data-views-current',current);if(element.scrollHeight<=(direction+element.offsetHeight+300)&&direction>0){element.classList.add('scroll-end')}
|
||||
else{element.classList.remove('scroll-end')}};window.addEventListener('scroll',check,false);window.addEventListener('resize',check,false);check();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-setup",controller:function(element,console,form,alerts,router){element.addEventListener("submit",function(event){event.preventDefault();let loaderId=alerts.add({text:'Creating new project...',class:""},0);let formData=form.toJson(element);formData["name"]=formData["name"]||(element.dataset["defaultName"]||"");console.teams.create('unique()',formData["name"]||"").then(function(data){let team=data["$id"];formData=JSON.parse(JSON.stringify(formData).replace(new RegExp("{{teamId}}","g"),team));console.projects.create(formData["projectId"],formData["name"],team,formData['region']).then(function(project){alerts.remove(loaderId);window.location.href="/console/home?project="+project["$id"];},function(){throw new Error("Failed to setup project");});},function(){throw new Error("Setup failed creating project team");});});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-switch",controller:function(element,router,document){let check=function(c){if(!element.value){return;}
|
||||
else{element.classList.remove('scroll-end')}};window.addEventListener('scroll',check,false);window.addEventListener('resize',check,false);check();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-setup",controller:function(element,console,form,alerts,router){element.addEventListener("submit",function(event){event.preventDefault();let loaderId=alerts.add({text:'Creating new project...',class:""},0);let formData=form.toJson(element);formData["name"]=formData["name"]||(element.dataset["defaultName"]||"");console.teams.create('unique()',formData["name"]||"").then(function(data){let team=data["$id"];formData=JSON.parse(JSON.stringify(formData).replace(new RegExp("{{teamId}}","g"),team));console.projects.create(formData["projectId"],formData["name"],team).then(function(project){alerts.remove(loaderId);window.location.href="/console/home?project="+project["$id"];},function(){throw new Error("Failed to setup project");});},function(){throw new Error("Setup failed creating project team");});});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-switch",controller:function(element,router,document){let check=function(c){if(!element.value){return;}
|
||||
if(element.value===router.params.project){return;}
|
||||
return router.change("/console/home?project="+element.value);};element.addEventListener("change",function(){check();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-general-theme",controller:function(element,router,document){let toggle=function(c){if(document.body.classList.contains('theme-light')){document.body.classList.remove('theme-light');document.body.classList.add('theme-dark');window.localStorage.setItem('user-theme','theme-dark')}
|
||||
else{document.body.classList.remove('theme-dark');document.body.classList.add('theme-light');window.localStorage.setItem('user-theme','theme-light')}};element.addEventListener("click",function(){toggle();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-version",controller:function(alerts,env,cookie){let cookieName="version-update-"+env.VERSION.replace(/\./g,"_");if(!cookie.get(cookieName)){var xhr=new XMLHttpRequest();xhr.open('GET','https://appwrite.io/version',true);xhr.onload=function(){if(this.readyState==4&&this.status==200){let data=JSON.parse(this.responseText);let text='Appwrite version '+data.version+' is available, check the';if(isNewerVersion(env.VERSION,data.version)){alerts.add({text:text,class:"success",link:"https://github.com/appwrite/appwrite/releases",label:'release notes',callback:function(){cookie.set(cookieName,"true",365*10);}},0);}}};xhr.send(null);function isNewerVersion(oldVer,newVer){const oldParts=oldVer.split('.')
|
||||
|
|
8
public/dist/scripts/app-dep.js
vendored
8
public/dist/scripts/app-dep.js
vendored
|
@ -519,14 +519,12 @@ class Projects extends Service{constructor(client){super(client);}
|
|||
list(queries,search){return __awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof queries!=='undefined'){payload['queries']=queries;}
|
||||
if(typeof search!=='undefined'){payload['search']=search;}
|
||||
const uri=new URL(this.client.config.endpoint+path);return yield this.client.call('get',uri,{'content-type':'application/json',},payload);});}
|
||||
create(projectId,name,teamId,region,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
create(projectId,name,teamId,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
if(typeof region==='undefined'){throw new AppwriteException('Missing required parameter: "region"');}
|
||||
let path='/projects';let payload={};if(typeof projectId!=='undefined'){payload['projectId']=projectId;}
|
||||
if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof teamId!=='undefined'){payload['teamId']=teamId;}
|
||||
if(typeof region!=='undefined'){payload['region']=region;}
|
||||
if(typeof description!=='undefined'){payload['description']=description;}
|
||||
if(typeof logo!=='undefined'){payload['logo']=logo;}
|
||||
if(typeof url!=='undefined'){payload['url']=url;}
|
||||
|
@ -539,11 +537,9 @@ if(typeof legalTaxId!=='undefined'){payload['legalTaxId']=legalTaxId;}
|
|||
const uri=new URL(this.client.config.endpoint+path);return yield this.client.call('post',uri,{'content-type':'application/json',},payload);});}
|
||||
get(projectId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.client.config.endpoint+path);return yield this.client.call('get',uri,{'content-type':'application/json',},payload);});}
|
||||
update(projectId,name,region,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
update(projectId,name,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId){return __awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof region==='undefined'){throw new AppwriteException('Missing required parameter: "region"');}
|
||||
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof region!=='undefined'){payload['region']=region;}
|
||||
if(typeof description!=='undefined'){payload['description']=description;}
|
||||
if(typeof logo!=='undefined'){payload['logo']=logo;}
|
||||
if(typeof url!=='undefined'){payload['url']=url;}
|
||||
|
|
4
public/dist/scripts/app.js
vendored
4
public/dist/scripts/app.js
vendored
|
@ -607,7 +607,7 @@ this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePer
|
|||
if(existing===undefined){let newPermission={role,create:false,read:false,update:false,xdelete:false,};newPermission[type]=true;this.permissions.push(newPermission);}
|
||||
if(index!==-1){existing[type]=true;this.permissions[index]=existing;}});},addPermission(formId){if(this.permissions.length>0&&!this.validate(formId,this.permissions.length-1)){return;}
|
||||
this.permissions.push({role:'',create:false,read:false,update:false,xdelete:false,});},updatePermission(index){setTimeout(()=>{const permission=this.permissions[index];Object.keys(permission).forEach(key=>{if(key==='role'){return;}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
const parsedKey=this.parseOutputPermission(key);const permissionString=this.buildPermission(parsedKey,permission.role);if(permission[key]){if(!this.rawPermissions.includes(permissionString)){this.rawPermissions.push(permissionString);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(permissionString);});}});});},clearPermission(index){let currentRole=this.permissions[index].role;this.rawPermissions=this.rawPermissions.filter(p=>{let{type,role}=this.parsePermission(p);return role!==currentRole;});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','').replaceAll('"','');return{type,role};},buildPermission(type,role){return`${type}("${role}")`},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
return key;},parseOutputPermission(key){if(key==='xdelete'){return'delete';}
|
||||
return key;},validate(formId,index){const form=document.getElementById(formId);const input=document.getElementById(`${formId}Input${index}`);const permission=this.permissions[index];input.setCustomValidity('');if(permission.role===''){input.setCustomValidity('Role is required');}else if(!Object.entries(permission).some(([k,v])=>!k.includes('role')&&v)){input.setCustomValidity('No permissions selected');}else if(this.permissions.some(p=>p.role===permission.role&&p!==permission)){input.setCustomValidity('Role entry already exists');}
|
||||
return form.reportValidity();},prevent(event){event.preventDefault();event.stopPropagation();}}));});})(window);(function(window){"use strict";window.ls.view.add({selector:"data-service",controller:function(element,view,container,form,alerts,expression,window){let action=element.dataset["service"];let service=element.dataset["name"]||null;let event=expression.parse(element.dataset["event"]);let confirm=element.dataset["confirm"]||"";let loading=element.dataset["loading"]||"";let loaderId=null;let scope=element.dataset["scope"]||"sdk";let success=element.dataset["success"]||"";let failure=element.dataset["failure"]||"";let running=false;let callbacks={hide:function(){return function(){return element.style.opacity='0';};},reset:function(){return function(){if("FORM"===element.tagName){return element.reset();}
|
||||
|
@ -739,7 +739,7 @@ element.classList.add('scroll-to-bottom')}
|
|||
else{element.classList.remove('scroll-to-bottom')
|
||||
element.classList.add('scroll-to-top')}
|
||||
position=direction;let current=Math.ceil(direction/window.innerHeight);element.setAttribute('data-views-total',Math.ceil(element.scrollHeight/window.innerHeight));element.setAttribute('data-views-current',current);if(element.scrollHeight<=(direction+element.offsetHeight+300)&&direction>0){element.classList.add('scroll-end')}
|
||||
else{element.classList.remove('scroll-end')}};window.addEventListener('scroll',check,false);window.addEventListener('resize',check,false);check();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-setup",controller:function(element,console,form,alerts,router){element.addEventListener("submit",function(event){event.preventDefault();let loaderId=alerts.add({text:'Creating new project...',class:""},0);let formData=form.toJson(element);formData["name"]=formData["name"]||(element.dataset["defaultName"]||"");console.teams.create('unique()',formData["name"]||"").then(function(data){let team=data["$id"];formData=JSON.parse(JSON.stringify(formData).replace(new RegExp("{{teamId}}","g"),team));console.projects.create(formData["projectId"],formData["name"],team,formData['region']).then(function(project){alerts.remove(loaderId);window.location.href="/console/home?project="+project["$id"];},function(){throw new Error("Failed to setup project");});},function(){throw new Error("Setup failed creating project team");});});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-switch",controller:function(element,router,document){let check=function(c){if(!element.value){return;}
|
||||
else{element.classList.remove('scroll-end')}};window.addEventListener('scroll',check,false);window.addEventListener('resize',check,false);check();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-setup",controller:function(element,console,form,alerts,router){element.addEventListener("submit",function(event){event.preventDefault();let loaderId=alerts.add({text:'Creating new project...',class:""},0);let formData=form.toJson(element);formData["name"]=formData["name"]||(element.dataset["defaultName"]||"");console.teams.create('unique()',formData["name"]||"").then(function(data){let team=data["$id"];formData=JSON.parse(JSON.stringify(formData).replace(new RegExp("{{teamId}}","g"),team));console.projects.create(formData["projectId"],formData["name"],team).then(function(project){alerts.remove(loaderId);window.location.href="/console/home?project="+project["$id"];},function(){throw new Error("Failed to setup project");});},function(){throw new Error("Setup failed creating project team");});});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-switch",controller:function(element,router,document){let check=function(c){if(!element.value){return;}
|
||||
if(element.value===router.params.project){return;}
|
||||
return router.change("/console/home?project="+element.value);};element.addEventListener("change",function(){check();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-general-theme",controller:function(element,router,document){let toggle=function(c){if(document.body.classList.contains('theme-light')){document.body.classList.remove('theme-light');document.body.classList.add('theme-dark');window.localStorage.setItem('user-theme','theme-dark')}
|
||||
else{document.body.classList.remove('theme-dark');document.body.classList.add('theme-light');window.localStorage.setItem('user-theme','theme-light')}};element.addEventListener("click",function(){toggle();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-version",controller:function(alerts,env,cookie){let cookieName="version-update-"+env.VERSION.replace(/\./g,"_");if(!cookie.get(cookieName)){var xhr=new XMLHttpRequest();xhr.open('GET','https://appwrite.io/version',true);xhr.onload=function(){if(this.readyState==4&&this.status==200){let data=JSON.parse(this.responseText);let text='Appwrite version '+data.version+' is available, check the';if(isNewerVersion(env.VERSION,data.version)){alerts.add({text:text,class:"success",link:"https://github.com/appwrite/appwrite/releases",label:'release notes',callback:function(){cookie.set(cookieName,"true",365*10);}},0);}}};xhr.send(null);function isNewerVersion(oldVer,newVer){const oldParts=oldVer.split('.')
|
||||
|
|
2
public/dist/styles/default-ltr.css
vendored
2
public/dist/styles/default-ltr.css
vendored
File diff suppressed because one or more lines are too long
2
public/dist/styles/default-rtl.css
vendored
2
public/dist/styles/default-rtl.css
vendored
File diff suppressed because one or more lines are too long
|
@ -4084,7 +4084,6 @@
|
|||
* @param {string} projectId
|
||||
* @param {string} name
|
||||
* @param {string} teamId
|
||||
* @param {string} region
|
||||
* @param {string} description
|
||||
* @param {string} logo
|
||||
* @param {string} url
|
||||
|
@ -4097,7 +4096,7 @@
|
|||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
create(projectId, name, teamId, region, description, logo, url, legalName, legalCountry, legalState, legalCity, legalAddress, legalTaxId) {
|
||||
create(projectId, name, teamId, description, logo, url, legalName, legalCountry, legalState, legalCity, legalAddress, legalTaxId) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof projectId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "projectId"');
|
||||
|
@ -4108,9 +4107,6 @@
|
|||
if (typeof teamId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "teamId"');
|
||||
}
|
||||
if (typeof region === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "region"');
|
||||
}
|
||||
let path = '/projects';
|
||||
let payload = {};
|
||||
if (typeof projectId !== 'undefined') {
|
||||
|
@ -4122,9 +4118,6 @@
|
|||
if (typeof teamId !== 'undefined') {
|
||||
payload['teamId'] = teamId;
|
||||
}
|
||||
if (typeof region !== 'undefined') {
|
||||
payload['region'] = region;
|
||||
}
|
||||
if (typeof description !== 'undefined') {
|
||||
payload['description'] = description;
|
||||
}
|
||||
|
@ -4185,7 +4178,6 @@
|
|||
*
|
||||
* @param {string} projectId
|
||||
* @param {string} name
|
||||
* @param {string} region
|
||||
* @param {string} description
|
||||
* @param {string} logo
|
||||
* @param {string} url
|
||||
|
@ -4198,7 +4190,7 @@
|
|||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
update(projectId, name, region, description, logo, url, legalName, legalCountry, legalState, legalCity, legalAddress, legalTaxId) {
|
||||
update(projectId, name, description, logo, url, legalName, legalCountry, legalState, legalCity, legalAddress, legalTaxId) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof projectId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "projectId"');
|
||||
|
@ -4206,17 +4198,11 @@
|
|||
if (typeof name === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "name"');
|
||||
}
|
||||
if (typeof region === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "region"');
|
||||
}
|
||||
let path = '/projects/{projectId}'.replace('{projectId}', projectId);
|
||||
let payload = {};
|
||||
if (typeof name !== 'undefined') {
|
||||
payload['name'] = name;
|
||||
}
|
||||
if (typeof region !== 'undefined') {
|
||||
payload['region'] = region;
|
||||
}
|
||||
if (typeof description !== 'undefined') {
|
||||
payload['description'] = description;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,14 @@
|
|||
});
|
||||
});
|
||||
},
|
||||
clearPermission(index) {
|
||||
let currentRole = this.permissions[index].role;
|
||||
this.rawPermissions = this.rawPermissions.filter(p => {
|
||||
let {type, role} = this.parsePermission(p);
|
||||
|
||||
return role !== currentRole;
|
||||
});
|
||||
},
|
||||
removePermission(index) {
|
||||
let row = this.permissions.splice(index, 1);
|
||||
if (row.length === 1) {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
)
|
||||
); //convert to JSON string
|
||||
|
||||
console.projects.create(formData["projectId"], formData["name"], team, formData['region']).then(
|
||||
console.projects.create(formData["projectId"], formData["name"], team).then(
|
||||
function(project) {
|
||||
alerts.remove(loaderId);
|
||||
//router.change("/console/home?project=" + project["$id"]);
|
||||
|
|
|
@ -836,6 +836,7 @@ label.switch {
|
|||
border-radius: 21px;
|
||||
background: var(--config-color-fade);
|
||||
display: inline-block;
|
||||
overflow: visible;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
.func-padding-start(5px);
|
||||
|
|
|
@ -44,6 +44,7 @@ abstract class Migration
|
|||
'1.0.0-RC1' => 'V15',
|
||||
'1.0.0' => 'V15',
|
||||
'1.0.1' => 'V15',
|
||||
'1.0.3' => 'V15'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -504,6 +504,7 @@ class V15 extends Migration
|
|||
$this->createPermissionsColumn($id);
|
||||
$this->migrateDateTimeAttribute($id, '_createdAt');
|
||||
$this->migrateDateTimeAttribute($id, '_updatedAt');
|
||||
$this->migrateDateTimeAttribute($id, 'time');
|
||||
break;
|
||||
|
||||
case 'buckets':
|
||||
|
|
|
@ -49,11 +49,17 @@ class URL extends Validator
|
|||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
if (\filter_var($value, FILTER_VALIDATE_URL) === false) {
|
||||
$sanitizedURL = '';
|
||||
|
||||
foreach (str_split($value) as $character) {
|
||||
$sanitizedURL .= (ord($character) > 127) ? rawurlencode($character) : $character;
|
||||
}
|
||||
|
||||
if (\filter_var($sanitizedURL, FILTER_VALIDATE_URL) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($this->allowedSchemes) && !\in_array(\parse_url($value, PHP_URL_SCHEME), $this->allowedSchemes)) {
|
||||
if (!empty($this->allowedSchemes) && !\in_array(\parse_url($sanitizedURL, PHP_URL_SCHEME), $this->allowedSchemes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,13 @@ namespace Appwrite\SMS\Adapter;
|
|||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Mock adapter used to E2E test worker
|
||||
class Mock extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static string $digits = '123456';
|
||||
private string $endpoint = 'http://request-catcher:5000/mock-sms';
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
|
@ -19,6 +20,19 @@ class Mock extends Adapter
|
|||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
return;
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: $this->endpoint,
|
||||
payload: \json_encode([
|
||||
'message' => $message,
|
||||
'from' => $from,
|
||||
'to' => $to
|
||||
]),
|
||||
headers: [
|
||||
"content-type: application/json",
|
||||
"x-username: {$this->user}",
|
||||
"x-key: {$this->secret}",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,5 @@ namespace Appwrite\Usage;
|
|||
|
||||
abstract class Calculator
|
||||
{
|
||||
protected string $region;
|
||||
|
||||
public function __construct(string $region)
|
||||
{
|
||||
$this->region = $region;
|
||||
}
|
||||
|
||||
abstract public function collect(): void;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Appwrite\Usage\Calculators;
|
||||
|
||||
use Exception;
|
||||
use Utopia\App;
|
||||
use Appwrite\Usage\Calculator;
|
||||
use DateTime;
|
||||
use Utopia\Database\Database as UtopiaDatabase;
|
||||
|
@ -25,9 +24,8 @@ class Database extends Calculator
|
|||
],
|
||||
];
|
||||
|
||||
public function __construct(string $region, UtopiaDatabase $database, callable $errorHandler = null)
|
||||
public function __construct(UtopiaDatabase $database, callable $errorHandler = null)
|
||||
{
|
||||
parent::__construct($region);
|
||||
$this->database = $database;
|
||||
$this->errorHandler = $errorHandler;
|
||||
}
|
||||
|
@ -97,7 +95,6 @@ class Database extends Calculator
|
|||
'time' => $time,
|
||||
'metric' => $metric,
|
||||
'value' => $value,
|
||||
'region' => $this->region,
|
||||
'type' => 2, // these are cumulative metrics
|
||||
]));
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Appwrite\Usage\Calculators;
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Usage\Calculator;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
|
@ -279,9 +278,8 @@ class TimeSeries extends Calculator
|
|||
'startTime' => '-24 hours',
|
||||
];
|
||||
|
||||
public function __construct(string $region, Database $database, InfluxDatabase $influxDB, callable $errorHandler = null)
|
||||
public function __construct(Database $database, InfluxDatabase $influxDB, callable $errorHandler = null)
|
||||
{
|
||||
parent::__construct($region);
|
||||
$this->database = $database;
|
||||
$this->influxDB = $influxDB;
|
||||
$this->errorHandler = $errorHandler;
|
||||
|
@ -317,7 +315,6 @@ class TimeSeries extends Calculator
|
|||
'metric' => $metric,
|
||||
'value' => $value,
|
||||
'type' => $type,
|
||||
'region' => $this->region,
|
||||
]));
|
||||
} else {
|
||||
$this->database->updateDocument(
|
||||
|
|
|
@ -91,20 +91,17 @@ class V15 extends Filter
|
|||
$parsedResponse[$listKey] = array_map(fn ($content) => $this->parseCreatedAtUpdatedAt($content), $parsedResponse[$listKey]);
|
||||
break;
|
||||
case Response::MODEL_DOCUMENT:
|
||||
$parsedResponse = $this->parseDocument($parsedResponse);
|
||||
break;
|
||||
case Response::MODEL_FILE:
|
||||
$parsedResponse = $this->parsePermissionsCreatedAtUpdatedAt($parsedResponse);
|
||||
break;
|
||||
case Response::MODEL_DOCUMENT_LIST:
|
||||
$listKey = 'documents';
|
||||
$parsedResponse[$listKey] = array_map(fn ($content) => $this->parseDocument($content), $parsedResponse[$listKey]);
|
||||
break;
|
||||
case Response::MODEL_FILE_LIST:
|
||||
$listKey = '';
|
||||
switch ($model) {
|
||||
case Response::MODEL_DOCUMENT_LIST:
|
||||
$listKey = 'documents';
|
||||
break;
|
||||
case Response::MODEL_FILE_LIST:
|
||||
$listKey = 'files';
|
||||
break;
|
||||
}
|
||||
$listKey = 'files';
|
||||
$parsedResponse[$listKey] = array_map(fn ($content) => $this->parsePermissionsCreatedAtUpdatedAt($content), $parsedResponse[$listKey]);
|
||||
break;
|
||||
case Response::MODEL_EXECUTION:
|
||||
|
@ -210,7 +207,11 @@ class V15 extends Filter
|
|||
protected function parseDatetimeAttributes(array $content, array $attributes): array
|
||||
{
|
||||
foreach ($attributes as $attribute) {
|
||||
if (isset($content[$attribute])) {
|
||||
if (array_key_exists($attribute, $content)) {
|
||||
if (empty($content[$attribute])) {
|
||||
$content[$attribute] = 0;
|
||||
continue;
|
||||
}
|
||||
$content[$attribute] = strtotime($content[$attribute]);
|
||||
}
|
||||
}
|
||||
|
@ -314,6 +315,19 @@ class V15 extends Filter
|
|||
return $content;
|
||||
}
|
||||
|
||||
protected function parseDocument(array $content)
|
||||
{
|
||||
if (isset($content['$collectionId'])) {
|
||||
$content['$collection'] = $content['$collectionId'];
|
||||
unset($content['$collectionId']);
|
||||
}
|
||||
|
||||
unset($content['$databaseId']);
|
||||
|
||||
$content = $this->parsePermissionsCreatedAtUpdatedAt($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function parseExecution($content)
|
||||
{
|
||||
unset($content['stdout']);
|
||||
|
|
|
@ -13,26 +13,26 @@ class AlgoScrypt extends Model
|
|||
->addRule('costCpu', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'CPU complexity of computed hash.',
|
||||
'default' => '',
|
||||
'default' => 8,
|
||||
'example' => 8,
|
||||
])
|
||||
->addRule('costMemory', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Memory complexity of computed hash.',
|
||||
'default' => '',
|
||||
'default' => 14,
|
||||
'example' => 14,
|
||||
])
|
||||
->addRule('costParallel', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Parallelization of computed hash.',
|
||||
'default' => '',
|
||||
'default' => 1,
|
||||
'example' => 1,
|
||||
])
|
||||
->addRule('length', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Length used to compute hash.',
|
||||
'default' => '',
|
||||
'example' => 1,
|
||||
'default' => 64,
|
||||
'example' => 64,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,15 @@ class UsageTest extends Scope
|
|||
parent::setUp();
|
||||
}
|
||||
|
||||
protected static string $formatTz = 'Y-m-d\TH:i:s.vP';
|
||||
|
||||
protected function validateDates(array $metrics): void
|
||||
{
|
||||
foreach ($metrics as $metric) {
|
||||
$this->assertIsObject(\DateTime::createFromFormat("Y-m-d\TH:i:s.vP", $metric['date']));
|
||||
}
|
||||
}
|
||||
|
||||
public function testPrepareUsersStats(): array
|
||||
{
|
||||
$project = $this->getProject(true);
|
||||
|
@ -97,7 +106,9 @@ class UsageTest extends Scope
|
|||
$this->assertEquals(30, count($res['requests']));
|
||||
$this->assertEquals(30, count($res['users']));
|
||||
$this->assertEquals($usersCount, $res['users'][array_key_last($res['users'])]['value']);
|
||||
$this->validateDates($res['users']);
|
||||
$this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']);
|
||||
$this->validateDates($res['requests']);
|
||||
|
||||
$res = $this->client->call(Client::METHOD_GET, '/users/usage?range=30d', array_merge($cheaders, [
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
@ -105,8 +116,11 @@ class UsageTest extends Scope
|
|||
]));
|
||||
$res = $res['body'];
|
||||
$this->assertEquals(10, $res['usersCreate'][array_key_last($res['usersCreate'])]['value']);
|
||||
$this->validateDates($res['usersCreate']);
|
||||
$this->assertEquals(5, $res['usersRead'][array_key_last($res['usersRead'])]['value']);
|
||||
$this->validateDates($res['usersRead']);
|
||||
$this->assertEquals(5, $res['usersDelete'][array_key_last($res['usersDelete'])]['value']);
|
||||
$this->validateDates($res['usersDelete']);
|
||||
|
||||
return ['projectId' => $projectId, 'headers' => $headers, 'requestsCount' => $requestsCount];
|
||||
}
|
||||
|
@ -176,7 +190,7 @@ class UsageTest extends Scope
|
|||
'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'),
|
||||
'name' => 'kitten-1.jpg',
|
||||
],
|
||||
];
|
||||
];
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$file = $files[$i % count($files)];
|
||||
|
@ -257,7 +271,9 @@ class UsageTest extends Scope
|
|||
$this->assertEquals(30, count($res['requests']));
|
||||
$this->assertEquals(30, count($res['storage']));
|
||||
$this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']);
|
||||
$this->validateDates($res['requests']);
|
||||
$this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']);
|
||||
$this->validateDates($res['storage']);
|
||||
|
||||
$res = $this->client->call(Client::METHOD_GET, '/storage/usage?range=30d', array_merge($headers, [
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
@ -265,14 +281,23 @@ class UsageTest extends Scope
|
|||
]));
|
||||
$res = $res['body'];
|
||||
$this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']);
|
||||
$this->validateDates($res['storage']);
|
||||
$this->assertEquals($bucketsCount, $res['bucketsCount'][array_key_last($res['bucketsCount'])]['value']);
|
||||
$this->validateDates($res['bucketsCount']);
|
||||
$this->assertEquals($bucketsRead, $res['bucketsRead'][array_key_last($res['bucketsRead'])]['value']);
|
||||
$this->validateDates($res['bucketsRead']);
|
||||
$this->assertEquals($bucketsCreate, $res['bucketsCreate'][array_key_last($res['bucketsCreate'])]['value']);
|
||||
$this->validateDates($res['bucketsCreate']);
|
||||
$this->assertEquals($bucketsDelete, $res['bucketsDelete'][array_key_last($res['bucketsDelete'])]['value']);
|
||||
$this->validateDates($res['bucketsDelete']);
|
||||
$this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']);
|
||||
$this->validateDates($res['filesCount']);
|
||||
$this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']);
|
||||
$this->validateDates($res['filesRead']);
|
||||
$this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']);
|
||||
$this->validateDates($res['filesCreate']);
|
||||
$this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']);
|
||||
$this->validateDates($res['filesDelete']);
|
||||
|
||||
$res = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage?range=30d', array_merge($headers, [
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
@ -483,8 +508,11 @@ class UsageTest extends Scope
|
|||
$this->assertEquals(30, count($res['requests']));
|
||||
$this->assertEquals(30, count($res['storage']));
|
||||
$this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']);
|
||||
$this->validateDates($res['requests']);
|
||||
$this->assertEquals($collectionsCount, $res['collections'][array_key_last($res['collections'])]['value']);
|
||||
$this->validateDates($res['collections']);
|
||||
$this->assertEquals($documentsCount, $res['documents'][array_key_last($res['documents'])]['value']);
|
||||
$this->validateDates($res['documents']);
|
||||
|
||||
$res = $this->client->call(Client::METHOD_GET, '/databases/usage?range=30d', array_merge($headers, [
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
@ -492,21 +520,34 @@ class UsageTest extends Scope
|
|||
]));
|
||||
$res = $res['body'];
|
||||
$this->assertEquals($databasesCount, $res['databasesCount'][array_key_last($res['databasesCount'])]['value']);
|
||||
$this->validateDates($res['databasesCount']);
|
||||
$this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']);
|
||||
$this->validateDates($res['collectionsCount']);
|
||||
$this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']);
|
||||
$this->validateDates($res['documentsCount']);
|
||||
|
||||
$this->assertEquals($databasesCreate, $res['databasesCreate'][array_key_last($res['databasesCreate'])]['value']);
|
||||
$this->validateDates($res['databasesCreate']);
|
||||
$this->assertEquals($databasesRead, $res['databasesRead'][array_key_last($res['databasesRead'])]['value']);
|
||||
$this->validateDates($res['databasesRead']);
|
||||
$this->assertEquals($databasesDelete, $res['databasesDelete'][array_key_last($res['databasesDelete'])]['value']);
|
||||
$this->validateDates($res['databasesDelete']);
|
||||
|
||||
$this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']);
|
||||
$this->validateDates($res['collectionsCreate']);
|
||||
$this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']);
|
||||
$this->validateDates($res['collectionsRead']);
|
||||
$this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']);
|
||||
$this->validateDates($res['collectionsUpdate']);
|
||||
$this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']);
|
||||
$this->validateDates($res['collectionsDelete']);
|
||||
|
||||
$this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']);
|
||||
$this->validateDates($res['documentsCreate']);
|
||||
$this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']);
|
||||
$this->validateDates($res['documentsRead']);
|
||||
$this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']);
|
||||
$this->validateDates($res['documentsDelete']);
|
||||
|
||||
$res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage?range=30d', array_merge($headers, [
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
@ -514,16 +555,25 @@ class UsageTest extends Scope
|
|||
]));
|
||||
$res = $res['body'];
|
||||
$this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']);
|
||||
$this->validateDates($res['collectionsCount']);
|
||||
$this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']);
|
||||
$this->validateDates($res['documentsCount']);
|
||||
|
||||
$this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']);
|
||||
$this->validateDates($res['collectionsCreate']);
|
||||
$this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']);
|
||||
$this->validateDates($res['collectionsRead']);
|
||||
$this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']);
|
||||
$this->validateDates($res['collectionsUpdate']);
|
||||
$this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']);
|
||||
$this->validateDates($res['collectionsDelete']);
|
||||
|
||||
$this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']);
|
||||
$this->validateDates($res['documentsCreate']);
|
||||
$this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']);
|
||||
$this->validateDates($res['documentsRead']);
|
||||
$this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']);
|
||||
$this->validateDates($res['documentsDelete']);
|
||||
|
||||
$res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', array_merge($headers, [
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
@ -531,10 +581,14 @@ class UsageTest extends Scope
|
|||
]));
|
||||
$res = $res['body'];
|
||||
$this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']);
|
||||
$this->validateDates($res['documentsCount']);
|
||||
|
||||
$this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']);
|
||||
$this->validateDates($res['documentsCreate']);
|
||||
$this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']);
|
||||
$this->validateDates($res['documentsRead']);
|
||||
$this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']);
|
||||
$this->validateDates($res['documentsDelete']);
|
||||
|
||||
$data['requestsCount'] = $requestsCount;
|
||||
return $data;
|
||||
|
@ -667,8 +721,11 @@ class UsageTest extends Scope
|
|||
$response = $response['body'];
|
||||
|
||||
$this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']);
|
||||
$this->validateDates($response['executionsTotal']);
|
||||
$this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']);
|
||||
$this->validateDates($response['executionsTime']);
|
||||
$this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']);
|
||||
$this->validateDates($response['executionsFailure']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/functions/usage', $headers, [
|
||||
'range' => '30d'
|
||||
|
@ -688,9 +745,13 @@ class UsageTest extends Scope
|
|||
$response = $response['body'];
|
||||
|
||||
$this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']);
|
||||
$this->validateDates($response['executionsTotal']);
|
||||
$this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']);
|
||||
$this->validateDates($response['executionsTime']);
|
||||
$this->assertGreaterThan(0, $response['buildsTime'][array_key_last($response['buildsTime'])]['value']);
|
||||
$this->validateDates($response['buildsTime']);
|
||||
$this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']);
|
||||
$this->validateDates($response['executionsFailure']);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
|
|
|
@ -42,7 +42,6 @@ trait ProjectCustom
|
|||
'x-appwrite-project' => 'console',
|
||||
], [
|
||||
'projectId' => ID::unique(),
|
||||
'region' => 'default',
|
||||
'name' => 'Demo Project',
|
||||
'teamId' => $team['body']['$id'],
|
||||
'description' => 'Demo Project Description',
|
||||
|
|
|
@ -716,7 +716,19 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$data['token'] = Mock::$digits;
|
||||
\sleep(2);
|
||||
|
||||
$smsRequest = $this->getLastRequest();
|
||||
|
||||
$this->assertEquals('http://request-catcher:5000/mock-sms', $smsRequest['url']);
|
||||
$this->assertEquals('Appwrite Phone Authentication', $smsRequest['headers']['User-Agent']);
|
||||
$this->assertEquals('username', $smsRequest['headers']['X-Username']);
|
||||
$this->assertEquals('password', $smsRequest['headers']['X-Key']);
|
||||
$this->assertEquals('POST', $smsRequest['method']);
|
||||
$this->assertEquals('+123456789', $smsRequest['data']['from']);
|
||||
$this->assertEquals($number, $smsRequest['data']['to']);
|
||||
|
||||
$data['token'] = $smsRequest['data']['message'];
|
||||
$data['id'] = $userId;
|
||||
$data['number'] = $number;
|
||||
|
||||
|
@ -931,7 +943,13 @@ class AccountCustomClientTest extends Scope
|
|||
$this->assertEmpty($response['body']['secret']);
|
||||
$this->assertEquals(true, DateTime::isValid($response['body']['expire']));
|
||||
|
||||
return $data;
|
||||
\sleep(2);
|
||||
|
||||
$smsRequest = $this->getLastRequest();
|
||||
|
||||
return \array_merge($data, [
|
||||
'token' => $smsRequest['data']['message']
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -941,6 +959,7 @@ class AccountCustomClientTest extends Scope
|
|||
{
|
||||
$id = $data['id'] ?? '';
|
||||
$session = $data['session'] ?? '';
|
||||
$secret = $data['token'] ?? '';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
|
@ -952,7 +971,7 @@ class AccountCustomClientTest extends Scope
|
|||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'userId' => $id,
|
||||
'secret' => Mock::$digits,
|
||||
'secret' => $secret,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
@ -967,7 +986,7 @@ class AccountCustomClientTest extends Scope
|
|||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'userId' => ID::custom('ewewe'),
|
||||
'secret' => Mock::$digits,
|
||||
'secret' => $secret,
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
|
|
@ -2968,4 +2968,52 @@ trait DatabasesBase
|
|||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateDatabase
|
||||
*/
|
||||
public function testAttributeBooleanDefault(array $data): void
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Boolean'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
$true = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'true',
|
||||
'required' => false,
|
||||
'default' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $true['headers']['status-code']);
|
||||
|
||||
$false = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/boolean', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'false',
|
||||
'required' => false,
|
||||
'default' => false
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $false['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Wait for deployment to be built.
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -228,7 +228,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
// Wait for deployment to be built.
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
|
@ -252,7 +252,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -326,7 +326,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
// Wait for deployment to be built.
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
|
@ -395,7 +395,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$base = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -556,7 +556,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Wait for deployment to be built.
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
|
|
@ -373,7 +373,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||
|
||||
// Wait for deployment to build.
|
||||
sleep(30);
|
||||
sleep(60);
|
||||
|
||||
return array_merge($data, ['deploymentId' => $deploymentId]);
|
||||
}
|
||||
|
@ -610,7 +610,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals('', $execution['body']['stderr']);
|
||||
$this->assertEquals(0, $execution['body']['duration']);
|
||||
|
||||
sleep(5);
|
||||
sleep(10);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -637,7 +637,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
return array_merge($data, ['executionId' => $executionId]);
|
||||
}
|
||||
|
@ -881,7 +881,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Allow build step to run
|
||||
sleep(20);
|
||||
sleep(40);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -894,7 +894,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -965,7 +965,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Allow build step to run
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -988,7 +988,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1087,7 +1087,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Allow build step to run
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1103,7 +1103,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1200,7 +1200,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Allow build step to run
|
||||
sleep(30);
|
||||
sleep(60);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1216,7 +1216,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
sleep(30);
|
||||
sleep(60);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1314,7 +1314,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Allow build step to run
|
||||
sleep(40);
|
||||
sleep(80);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1330,7 +1330,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1428,7 +1428,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Allow build step to run
|
||||
sleep(30);
|
||||
sleep(60);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1444,7 +1444,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
|
@ -42,7 +42,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'projectId' => ID::unique(),
|
||||
'name' => 'Project Test',
|
||||
'teamId' => $team['body']['$id'],
|
||||
'region' => 'default',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
@ -65,7 +64,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'projectId' => ID::unique(),
|
||||
'name' => '',
|
||||
'teamId' => $team['body']['$id'],
|
||||
'region' => 'default'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
@ -76,7 +74,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
], $this->getHeaders()), [
|
||||
'projectId' => ID::unique(),
|
||||
'name' => 'Project Test',
|
||||
'region' => 'default'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
@ -156,7 +153,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'projectId' => ID::unique(),
|
||||
'name' => 'Project Test 2',
|
||||
'teamId' => $team['body']['$id'],
|
||||
'region' => 'default'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
@ -692,7 +688,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'projectId' => ID::unique(),
|
||||
'name' => 'Project Test',
|
||||
'teamId' => $team['body']['$id'],
|
||||
'region' => 'default'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $project['headers']['status-code']);
|
||||
|
|
|
@ -126,6 +126,52 @@ trait TeamsBaseClient
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTeamMembership
|
||||
*/
|
||||
public function testGetTeamMembership($data): void
|
||||
{
|
||||
$teamUid = $data['teamUid'] ?? '';
|
||||
$membershipUid = $data['membershipUid'] ?? '';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertNotEmpty($response['body']['userId']);
|
||||
$this->assertNotEmpty($response['body']['userName']);
|
||||
$this->assertNotEmpty($response['body']['userEmail']);
|
||||
$this->assertNotEmpty($response['body']['teamId']);
|
||||
$this->assertNotEmpty($response['body']['teamName']);
|
||||
$this->assertCount(2, $response['body']['roles']);
|
||||
$this->assertEquals(false, DateTime::isValid($response['body']['joined'])); // is null in DB
|
||||
$this->assertEquals(false, $response['body']['confirm']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid . 'dasdasd', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTeam
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,51 @@ trait TeamsBaseServer
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTeamMembership
|
||||
*/
|
||||
public function testGetTeamMembership($data): void
|
||||
{
|
||||
$teamUid = $data['teamUid'] ?? '';
|
||||
$membershipUid = $data['membershipUid'] ?? '';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertNotEmpty($response['body']['userId']);
|
||||
$this->assertNotEmpty($response['body']['userName']);
|
||||
$this->assertNotEmpty($response['body']['userEmail']);
|
||||
$this->assertNotEmpty($response['body']['teamId']);
|
||||
$this->assertNotEmpty($response['body']['teamName']);
|
||||
$this->assertCount(2, $response['body']['roles']);
|
||||
$this->assertEquals(true, DateTime::isValid($response['body']['joined'])); // is null in DB
|
||||
$this->assertEquals(true, $response['body']['confirm']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid . 'dasdasd', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTeam
|
||||
|
|
|
@ -180,89 +180,51 @@ trait UsersBase
|
|||
*/
|
||||
public function testCreateUserSessionHashed(array $data): void
|
||||
{
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'md5@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
$userIds = [ 'md5', 'bcrypt', 'argon2', 'sha512', 'scrypt', 'phpass', 'scrypt-modified' ];
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'md5');
|
||||
foreach ($userIds as $userId) {
|
||||
// Ensure sessions can be created with hashed passwords
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $userId . '@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'bcrypt@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertEquals($userId, $response['body']['userId']);
|
||||
}
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'bcrypt');
|
||||
foreach ($userIds as $userId) {
|
||||
// Ensure all passwords were re-hashed
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'argon2@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($userId, $response['body']['$id']);
|
||||
$this->assertEquals($userId . '@appwrite.io', $response['body']['email']);
|
||||
$this->assertEquals('argon2', $response['body']['hash']);
|
||||
$this->assertStringStartsWith('$argon2', $response['body']['password']);
|
||||
}
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'argon2');
|
||||
foreach ($userIds as $userId) {
|
||||
// Ensure sessions can be created after re-hashing of passwords
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $userId . '@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'sha512@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'sha512');
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'scrypt@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'scrypt');
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'phpass@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'phpass');
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => 'scrypt-modified@appwrite.io',
|
||||
'password' => 'appwrite',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals($response['body']['userId'], 'scrypt-modified');
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertEquals($userId, $response['body']['userId']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -964,6 +926,81 @@ trait UsersBase
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGetUser
|
||||
*/
|
||||
public function testUpdateUserNumber(array $data): array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$updatedNumber = "+910000000000"; //dummy number
|
||||
$user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/phone', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'number' => $updatedNumber,
|
||||
]);
|
||||
|
||||
$this->assertEquals($user['headers']['status-code'], 200);
|
||||
$this->assertEquals($user['body']['phone'], $updatedNumber);
|
||||
|
||||
$user = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($user['headers']['status-code'], 200);
|
||||
$this->assertEquals($user['body']['phone'], $updatedNumber);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$errorType = "user_phone_already_exists";
|
||||
$user1Id = "user1";
|
||||
$statusCodeForUserPhoneAlredyExists = 409;
|
||||
|
||||
// adding same number ($updatedNumber) to different user i.e user1
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/users/' . $user1Id . '/phone', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'number' => $updatedNumber,
|
||||
]);
|
||||
$this->assertEquals($response['headers']['status-code'], $statusCodeForUserPhoneAlredyExists);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals($response['body']['type'], $errorType);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdateUserNumber
|
||||
*/
|
||||
public function testUpdateUserNumberSearch($data): void
|
||||
{
|
||||
$id = $data['userId'] ?? '';
|
||||
$newNumber = "+910000000000"; //dummy number
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => $newNumber,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['users']);
|
||||
$this->assertCount(1, $response['body']['users']);
|
||||
$this->assertEquals($response['body']['users'][0]['$id'], $id);
|
||||
$this->assertEquals($response['body']['users'][0]['phone'], $newNumber);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testGetUser
|
||||
|
|
|
@ -634,7 +634,7 @@ class WebhooksCustomServerTest extends Scope
|
|||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
|
||||
// wait for timeout function to complete
|
||||
sleep(10);
|
||||
sleep(20);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
|
|
@ -43,6 +43,7 @@ class URLTest extends TestCase
|
|||
$this->assertEquals(false, $this->url->isValid('htt@s://example.com'));
|
||||
$this->assertEquals(true, $this->url->isValid('http://www.example.com/foo%2\u00c2\u00a9zbar'));
|
||||
$this->assertEquals(true, $this->url->isValid('http://www.example.com/?q=%3Casdf%3E'));
|
||||
$this->assertEquals(true, $this->url->isValid('https://example.com/foo%2\u00c2\u00ä9zbär'));
|
||||
}
|
||||
|
||||
public function testIsValidAllowedSchemes(): void
|
||||
|
|
|
@ -502,9 +502,34 @@ class V15Test extends TestCase
|
|||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
public function documentProvider(): array
|
||||
{
|
||||
return [
|
||||
'basic document' => [
|
||||
[
|
||||
'$id' => '5e5ea5c16897e',
|
||||
'$collectionId' => '5e5ea5c15117e',
|
||||
'$databaseId' => '5e5ea5c15117e',
|
||||
'$createdAt' => '2020-06-24T06:47:30.000Z',
|
||||
'$updatedAt' => '2020-06-24T06:47:30.000Z',
|
||||
'$permissions' => [Permission::read(Role::any())]
|
||||
],
|
||||
[
|
||||
'$id' => '5e5ea5c16897e',
|
||||
'$collection' => '5e5ea5c15117e',
|
||||
'$createdAt' => 1592981250,
|
||||
'$updatedAt' => 1592981250,
|
||||
'$read' => ['role:all'],
|
||||
'$write' => [],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider createdAtUpdatedAtProvider
|
||||
* @dataProvider permissionsProvider
|
||||
* @dataProvider documentProvider
|
||||
*/
|
||||
public function testDocument(array $content, array $expected): void
|
||||
{
|
||||
|
@ -1077,6 +1102,14 @@ class V15Test extends TestCase
|
|||
'providerAccessTokenExpiry' => 1592981250,
|
||||
],
|
||||
],
|
||||
'empty values' => [
|
||||
[
|
||||
'providerAccessTokenExpiry' => '',
|
||||
],
|
||||
[
|
||||
'providerAccessTokenExpiry' => 0,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1122,7 @@ class V15Test extends TestCase
|
|||
|
||||
$result = $this->filter->parse($content, $model);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue