Merge remote-tracking branch 'origin/feat-database-indexing' into feat-db-search-attribute
This commit is contained in:
commit
f2c678bf41
19
.travis.yml
19
.travis.yml
|
@ -1,11 +1,15 @@
|
|||
dist: xenial
|
||||
dist: focal
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- arm64-graviton2
|
||||
|
||||
os: linux
|
||||
|
||||
# Small change
|
||||
vm:
|
||||
size: large
|
||||
|
||||
language: shell
|
||||
|
||||
notifications:
|
||||
|
@ -30,11 +34,17 @@ before_install:
|
|||
- echo "_APP_FUNCTIONS_RUNTIMES=php-8.0" >> .env
|
||||
|
||||
install:
|
||||
- docker-compose up -d
|
||||
- docker-compose up -d --build
|
||||
- sleep 10
|
||||
|
||||
script:
|
||||
- docker ps -a
|
||||
# Tests should fail if any container is in exited status
|
||||
- ALL_UP=`docker ps -aq --filter "status=exited"`
|
||||
- >
|
||||
if [[ "$ALL_UP" != "" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
- docker-compose logs appwrite
|
||||
- docker-compose logs mariadb
|
||||
- docker-compose logs appwrite-worker-functions
|
||||
|
@ -43,6 +53,9 @@ script:
|
|||
- docker-compose exec appwrite test --debug
|
||||
- docker-compose logs appwrite
|
||||
|
||||
after_failure:
|
||||
- docker-compose logs appwrite
|
||||
|
||||
deploy:
|
||||
- provider: script
|
||||
edge: true
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
- Grouped oAuth related attributes in project collection. Introduced new attribute `providers` and removed all attributes related to OAuth2 providers. All OAuth2 attributes are grouped under `providers`
|
||||
- Project model changed, `userAuth<AuthMethod>` => `auth<AuthMethod>` example `userAuthEmailPassword` => `authEmailPassword`, also `userOauth2<Provider>...` => `provider<Provider>...` example `userOauth2GithubAppid` => `providerGithubAppid`
|
||||
|
||||
# Version 0.9.4
|
||||
|
||||
## Security
|
||||
|
||||
- Fixed security vulnerability that exposes project ID's from other admin users (#1453)
|
||||
|
||||
# Version 0.9.3
|
||||
|
||||
## Bugs
|
||||
|
|
|
@ -19,8 +19,8 @@ ENV DEBUG=$DEBUG
|
|||
|
||||
ENV PHP_REDIS_VERSION=5.3.4 \
|
||||
PHP_MONGODB_VERSION=1.9.1 \
|
||||
PHP_SWOOLE_VERSION=v4.6.7 \
|
||||
PHP_IMAGICK_VERSION=3.5.0 \
|
||||
PHP_SWOOLE_VERSION=v4.7.0 \
|
||||
PHP_IMAGICK_VERSION=3.5.1 \
|
||||
PHP_YAML_VERSION=2.2.1 \
|
||||
PHP_MAXMINDDB_VERSION=v1.10.1
|
||||
|
||||
|
@ -225,6 +225,7 @@ RUN mkdir -p /storage/uploads && \
|
|||
# Executables
|
||||
RUN chmod +x /usr/local/bin/doctor && \
|
||||
chmod +x /usr/local/bin/maintenance && \
|
||||
chmod +x /usr/local/bin/usage && \
|
||||
chmod +x /usr/local/bin/install && \
|
||||
chmod +x /usr/local/bin/migrate && \
|
||||
chmod +x /usr/local/bin/schedule && \
|
||||
|
|
|
@ -57,7 +57,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:0.9.3
|
||||
appwrite/appwrite:0.9.4
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
@ -69,7 +69,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:0.9.3
|
||||
appwrite/appwrite:0.9.4
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
@ -79,7 +79,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:0.9.3
|
||||
appwrite/appwrite:0.9.4
|
||||
```
|
||||
|
||||
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.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/workers.php';
|
||||
require_once __DIR__.'/init.php';
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\CLI;
|
||||
|
@ -15,6 +15,7 @@ include 'tasks/migrate.php';
|
|||
include 'tasks/sdks.php';
|
||||
include 'tasks/ssl.php';
|
||||
include 'tasks/vars.php';
|
||||
include 'tasks/usage.php';
|
||||
|
||||
$cli
|
||||
->task('version')
|
||||
|
|
|
@ -7,8 +7,333 @@ $providers = Config::getParam('providers', []);
|
|||
$auth = Config::getParam('auth', []);
|
||||
|
||||
$collections = [
|
||||
'collections' => [
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'collections',
|
||||
'name' => 'Collections',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'name',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateUpdated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'permission',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 64,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'attributes',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 1000000,
|
||||
'required' => false,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryAttributes'],
|
||||
],
|
||||
[
|
||||
'$id' => 'indexes',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 1000000,
|
||||
'required' => false,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryIndexes'],
|
||||
],
|
||||
[
|
||||
'$id' => 'search',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_fulltext_search',
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['search'],
|
||||
'lengths' => [1024],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'attributes',
|
||||
'name' => 'Attributes',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'collectionId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'key',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'type',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'status',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'size',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'required',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'default',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['casting'],
|
||||
],
|
||||
[
|
||||
'$id' => 'signed',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'array',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'format',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 64,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'formatOptions',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => new stdClass,
|
||||
'array' => false,
|
||||
'filters' => ['json', 'range'],
|
||||
],
|
||||
[
|
||||
'$id' => 'filters',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 64,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_collection',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['collectionId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'indexes' => [
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'indexes',
|
||||
'name' => 'Indexes',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'collectionId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'key',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'type',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'status',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'attributes',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'lengths',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'orders',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 4,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_collection',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['collectionId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'projects' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'projects',
|
||||
'name' => 'Projects',
|
||||
'attributes' => [
|
||||
|
@ -245,7 +570,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'users' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'users',
|
||||
'name' => 'Users',
|
||||
'attributes' => [
|
||||
|
@ -412,7 +737,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'sessions' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'sessions',
|
||||
'name' => 'Sessions',
|
||||
'attributes' => [
|
||||
|
@ -660,7 +985,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'teams' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'teams',
|
||||
'name' => 'Teams',
|
||||
'attributes' => [
|
||||
|
@ -721,7 +1046,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'memberships' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'memberships',
|
||||
'name' => 'Memberships',
|
||||
'attributes' => [
|
||||
|
@ -829,7 +1154,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'files' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'files',
|
||||
'name' => 'Files',
|
||||
'attributes' => [
|
||||
|
@ -1019,7 +1344,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'functions' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'functions',
|
||||
'name' => 'Functions',
|
||||
'attributes' => [
|
||||
|
@ -1191,7 +1516,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'tags' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'tags',
|
||||
'name' => 'Tags',
|
||||
'attributes' => [
|
||||
|
@ -1282,7 +1607,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'executions' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'executions',
|
||||
'name' => 'Executions',
|
||||
'attributes' => [
|
||||
|
@ -1399,7 +1724,7 @@ $collections = [
|
|||
],
|
||||
|
||||
'certificates' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'certificates',
|
||||
'name' => 'Certificates',
|
||||
'attributes' => [
|
||||
|
@ -1483,6 +1808,91 @@ $collections = [
|
|||
],
|
||||
],
|
||||
],
|
||||
'stats' => [
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'stats',
|
||||
'name' => 'Stats',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'metric',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'value',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'time',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'period',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 4,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'type',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 1,
|
||||
'signed' => false,
|
||||
'required' => true,
|
||||
'default' => 0, // 0 -> count, 1 -> sum
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_time',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['time'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_DESC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_metric',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['metric'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_metric_period',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['metric', 'period'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_DESC],
|
||||
],
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
return $collections;
|
|
@ -27,6 +27,21 @@ return [
|
|||
'model' => Response::MODEL_USER,
|
||||
'note' => '',
|
||||
],
|
||||
'users.update.email' => [
|
||||
'description' => 'This event triggers when the user email address is updated.',
|
||||
'model' => Response::MODEL_USER,
|
||||
'note' => '',
|
||||
],
|
||||
'users.update.name' => [
|
||||
'description' => 'This event triggers when the user name is updated.',
|
||||
'model' => Response::MODEL_USER,
|
||||
'note' => '',
|
||||
],
|
||||
'users.update.password' => [
|
||||
'description' => 'This event triggers when the user password is updated.',
|
||||
'model' => Response::MODEL_USER,
|
||||
'note' => '',
|
||||
],
|
||||
'account.update.prefs' => [
|
||||
'description' => 'This event triggers when the account preferences are updated.',
|
||||
'model' => Response::MODEL_USER,
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -149,6 +149,15 @@ return [
|
|||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_AGGREGATION_INTERVAL',
|
||||
'description' => 'Interval value containing the number of seconds that the Appwrite usage process should wait before aggregating stats and syncing it to mariadb from InfluxDB. The default value is 30 seconds.',
|
||||
'introduction' => '0.10.0',
|
||||
'default' => '30',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
]
|
||||
],
|
||||
],
|
||||
|
|
|
@ -43,7 +43,7 @@ App::post('/v1/account')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->label('abuse-limit', 10)
|
||||
->param('userId', '', 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, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
|
||||
->param('userId', '', 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('email', '', new Email(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
|
@ -52,12 +52,14 @@ App::post('/v1/account')
|
|||
->inject('project')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($userId, $email, $password, $name, $request, $response, $project, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $email, $password, $name, $request, $response, $project, $dbForInternal, $audits, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$email = \strtolower($email);
|
||||
if ('console' === $project->getId()) {
|
||||
|
@ -118,9 +120,12 @@ App::post('/v1/account')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.create')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.create', 1)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
@ -148,13 +153,15 @@ App::post('/v1/account/sessions')
|
|||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audits')
|
||||
->action(function ($email, $password, $request, $response, $dbForInternal, $locale, $geodb, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($email, $password, $request, $response, $dbForInternal, $locale, $geodb, $audits, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$email = \strtolower($email);
|
||||
$protocol = $request->getProtocol();
|
||||
|
@ -165,7 +172,7 @@ App::post('/v1/account/sessions')
|
|||
$audits
|
||||
//->setParam('userId', $profile->getId())
|
||||
->setParam('event', 'account.sessions.failed')
|
||||
->setParam('resource', 'users/'.($profile ? $profile->getId() : ''))
|
||||
->setParam('resource', 'user/'.($profile ? $profile->getId() : ''))
|
||||
;
|
||||
|
||||
throw new Exception('Invalid credentials', 401); // Wrong password or username
|
||||
|
@ -206,7 +213,7 @@ App::post('/v1/account/sessions')
|
|||
$audits
|
||||
->setParam('userId', $profile->getId())
|
||||
->setParam('event', 'account.sessions.create')
|
||||
->setParam('resource', 'users/' . $profile->getId())
|
||||
->setParam('resource', 'user/' . $profile->getId())
|
||||
;
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
|
@ -228,6 +235,11 @@ App::post('/v1/account/sessions')
|
|||
->setAttribute('countryName', $countryName)
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
->setParam('users.sessions.create', 1)
|
||||
->setParam('provider', 'email')
|
||||
;
|
||||
$response->dynamic($session, Response::MODEL_SESSION);
|
||||
});
|
||||
|
||||
|
@ -358,7 +370,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
->inject('geodb')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($provider, $code, $state, $request, $response, $project, $user, $dbForInternal, $geodb, $audits, $events) use ($oauthDefaultSuccess) {
|
||||
->inject('usage')
|
||||
->action(function ($provider, $code, $state, $request, $response, $project, $user, $dbForInternal, $geodb, $audits, $events, $usage) use ($oauthDefaultSuccess) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
@ -366,6 +379,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
|
@ -541,12 +555,17 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.sessions.create')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
->setParam('data', ['provider' => $provider])
|
||||
;
|
||||
|
||||
$events->setParam('eventData', $response->output($session, Response::MODEL_SESSION));
|
||||
|
||||
$usage
|
||||
->setParam('users.sessions.create', 1)
|
||||
->setParam('projectId', $project->getId())
|
||||
->setParam('provider', 'oauth2-'.$provider)
|
||||
;
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
$response
|
||||
->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
|
||||
|
@ -597,7 +616,8 @@ App::post('/v1/account/sessions/anonymous')
|
|||
->inject('dbForInternal')
|
||||
->inject('geodb')
|
||||
->inject('audits')
|
||||
->action(function ($request, $response, $locale, $user, $project, $dbForInternal, $geodb, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($request, $response, $locale, $user, $project, $dbForInternal, $geodb, $audits, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
|
@ -606,6 +626,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
|
@ -686,7 +707,12 @@ App::post('/v1/account/sessions/anonymous')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.sessions.create')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.sessions.create', 1)
|
||||
->setParam('provider', 'anonymous')
|
||||
;
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
|
@ -774,10 +800,15 @@ App::get('/v1/account')
|
|||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function ($response, $user) {
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -794,12 +825,17 @@ App::get('/v1/account/prefs')
|
|||
->label('sdk.response.model', Response::MODEL_PREFERENCES)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function ($response, $user) {
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$prefs = $user->getAttribute('prefs', new \stdClass());
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
|
||||
});
|
||||
|
||||
|
@ -817,10 +853,12 @@ App::get('/v1/account/sessions')
|
|||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
->action(function ($response, $user, $locale) {
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $locale, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = Auth::sessionVerify($sessions, Auth::$secret);
|
||||
|
@ -834,6 +872,9 @@ App::get('/v1/account/sessions')
|
|||
$sessions[$key] = $session;
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic(new Document([
|
||||
'sessions' => $sessions,
|
||||
'sum' => count($sessions),
|
||||
|
@ -856,13 +897,15 @@ App::get('/v1/account/logs')
|
|||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($response, $user, $locale, $geodb, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($response, $user, $locale, $geodb, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$audit = new Audit($dbForInternal);
|
||||
|
||||
|
@ -909,6 +952,9 @@ App::get('/v1/account/logs')
|
|||
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic(new Document(['logs' => $output]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
|
@ -928,11 +974,13 @@ App::get('/v1/account/sessions/:sessionId')
|
|||
->inject('user')
|
||||
->inject('locale')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($sessionId, $response, $user, $locale, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($sessionId, $response, $user, $locale, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$sessionId = ($sessionId === 'current')
|
||||
|
@ -951,6 +999,10 @@ App::get('/v1/account/sessions/:sessionId')
|
|||
->setAttribute('countryName', $countryName)
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
|
||||
return $response->dynamic($session, Response::MODEL_SESSION);
|
||||
}
|
||||
}
|
||||
|
@ -975,11 +1027,13 @@ App::patch('/v1/account/name')
|
|||
->inject('user')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($name, $response, $user, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($name, $response, $user, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user
|
||||
->setAttribute('name', $name)
|
||||
|
@ -989,7 +1043,11 @@ App::patch('/v1/account/name')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.update.name')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
|
@ -1013,11 +1071,13 @@ App::patch('/v1/account/password')
|
|||
->inject('user')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($password, $oldPassword, $response, $user, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($password, $oldPassword, $response, $user, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
// Check old password only if its an existing user.
|
||||
if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password
|
||||
|
@ -1032,9 +1092,12 @@ App::patch('/v1/account/password')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.update.password')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -1056,11 +1119,13 @@ App::patch('/v1/account/email')
|
|||
->inject('user')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($email, $password, $response, $user, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($email, $password, $response, $user, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password')); // Check if request is from an anonymous account for converting
|
||||
|
||||
|
@ -1072,25 +1137,32 @@ App::patch('/v1/account/email')
|
|||
}
|
||||
|
||||
$email = \strtolower($email);
|
||||
$profile = $dbForInternal->findOne('users', [new Query('email', Query::TYPE_EQUAL, [\strtolower($email)])]); // Get user by email address
|
||||
$profile = $dbForInternal->findOne('users', [new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address
|
||||
|
||||
if ($profile) {
|
||||
throw new Exception('User already registered', 400);
|
||||
}
|
||||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user
|
||||
->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password) : $user->getAttribute('password', ''))
|
||||
->setAttribute('email', $email)
|
||||
->setAttribute('emailVerification', false) // After this user needs to confirm mail again
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')]))
|
||||
);
|
||||
try {
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user
|
||||
->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password) : $user->getAttribute('password', ''))
|
||||
->setAttribute('email', $email)
|
||||
->setAttribute('emailVerification', false) // After this user needs to confirm mail again
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')]))
|
||||
);
|
||||
} catch(Duplicate $th) {
|
||||
throw new Exception('Email already exists', 409);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.update.email')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -1111,19 +1183,24 @@ App::patch('/v1/account/prefs')
|
|||
->inject('user')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($prefs, $response, $user, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($prefs, $response, $user, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
|
||||
|
||||
$audits
|
||||
->setParam('event', 'account.update.prefs')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -1144,13 +1221,15 @@ App::delete('/v1/account')
|
|||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($request, $response, $user, $dbForInternal, $audits, $events) {
|
||||
->inject('usage')
|
||||
->action(function ($request, $response, $user, $dbForInternal, $audits, $events, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
|
||||
|
@ -1166,7 +1245,7 @@ App::delete('/v1/account')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.delete')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
->setParam('data', $user->getArrayCopy())
|
||||
;
|
||||
|
||||
|
@ -1180,6 +1259,9 @@ App::delete('/v1/account')
|
|||
;
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.delete', 1)
|
||||
;
|
||||
$response
|
||||
->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
|
@ -1207,7 +1289,8 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
->inject('locale')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($sessionId, $request, $response, $user, $dbForInternal, $locale, $audits, $events) {
|
||||
->inject('usage')
|
||||
->action(function ($sessionId, $request, $response, $user, $dbForInternal, $locale, $audits, $events, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
|
@ -1215,6 +1298,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$sessionId = ($sessionId === 'current')
|
||||
|
@ -1232,7 +1316,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.sessions.delete')
|
||||
->setParam('resource', '/user/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$session->setAttribute('current', false);
|
||||
|
@ -1261,6 +1345,10 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
->setParam('eventData', $response->output($session, Response::MODEL_SESSION))
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.sessions.delete', 1)
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
return $response->noContent();
|
||||
}
|
||||
}
|
||||
|
@ -1287,7 +1375,8 @@ App::delete('/v1/account/sessions')
|
|||
->inject('locale')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($request, $response, $user, $dbForInternal, $locale, $audits, $events) {
|
||||
->inject('usage')
|
||||
->action(function ($request, $response, $user, $dbForInternal, $locale, $audits, $events, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
|
@ -1295,6 +1384,7 @@ App::delete('/v1/account/sessions')
|
|||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
@ -1305,7 +1395,7 @@ App::delete('/v1/account/sessions')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.sessions.delete')
|
||||
->setParam('resource', '/user/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
|
@ -1330,13 +1420,19 @@ App::delete('/v1/account/sessions')
|
|||
|
||||
$dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('sessions', []));
|
||||
|
||||
$numOfSessions = count($sessions);
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output(new Document([
|
||||
'sessions' => $sessions,
|
||||
'sum' => count($sessions),
|
||||
'sum' => $numOfSessions,
|
||||
]), Response::MODEL_SESSION_LIST))
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.sessions.delete', $numOfSessions)
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
@ -1364,7 +1460,8 @@ App::post('/v1/account/recovery')
|
|||
->inject('mails')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($email, $url, $request, $response, $dbForInternal, $project, $locale, $mails, $audits, $events) {
|
||||
->inject('usage')
|
||||
->action(function ($email, $url, $request, $response, $dbForInternal, $project, $locale, $mails, $audits, $events, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
@ -1373,6 +1470,7 @@ App::post('/v1/account/recovery')
|
|||
/** @var Appwrite\Event\Event $mails */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
|
||||
$isAppUser = Auth::isAppUser(Authorization::$roles);
|
||||
|
@ -1437,9 +1535,12 @@ App::post('/v1/account/recovery')
|
|||
$audits
|
||||
->setParam('userId', $profile->getId())
|
||||
->setParam('event', 'account.recovery.create')
|
||||
->setParam('resource', 'users/' . $profile->getId())
|
||||
->setParam('resource', 'user/' . $profile->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($recovery, Response::MODEL_TOKEN);
|
||||
});
|
||||
|
@ -1465,10 +1566,12 @@ App::put('/v1/account/recovery')
|
|||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($userId, $secret, $password, $passwordAgain, $response, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $secret, $password, $passwordAgain, $response, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
if ($password !== $passwordAgain) {
|
||||
throw new Exception('Passwords must match', 400);
|
||||
|
@ -1511,9 +1614,12 @@ App::put('/v1/account/recovery')
|
|||
$audits
|
||||
->setParam('userId', $profile->getId())
|
||||
->setParam('event', 'account.recovery.update')
|
||||
->setParam('resource', 'users/' . $profile->getId())
|
||||
->setParam('resource', 'user/' . $profile->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($recovery, Response::MODEL_TOKEN);
|
||||
});
|
||||
|
||||
|
@ -1541,7 +1647,8 @@ App::post('/v1/account/verification')
|
|||
->inject('audits')
|
||||
->inject('events')
|
||||
->inject('mails')
|
||||
->action(function ($url, $request, $response, $project, $user, $dbForInternal, $locale, $audits, $events, $mails) {
|
||||
->inject('usage')
|
||||
->action(function ($url, $request, $response, $project, $user, $dbForInternal, $locale, $audits, $events, $mails, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
@ -1551,6 +1658,7 @@ App::post('/v1/account/verification')
|
|||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $mails */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
|
||||
$isAppUser = Auth::isAppUser(Authorization::$roles);
|
||||
|
@ -1605,9 +1713,12 @@ App::post('/v1/account/verification')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.verification.create')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($verification, Response::MODEL_TOKEN);
|
||||
});
|
||||
|
@ -1632,11 +1743,13 @@ App::put('/v1/account/verification')
|
|||
->inject('user')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($userId, $secret, $response, $user, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $secret, $response, $user, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$profile = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -1671,8 +1784,11 @@ App::put('/v1/account/verification')
|
|||
$audits
|
||||
->setParam('userId', $profile->getId())
|
||||
->setParam('event', 'account.verification.update')
|
||||
->setParam('resource', 'users/' . $user->getId())
|
||||
->setParam('resource', 'user/' . $user->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($verification, Response::MODEL_TOKEN);
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -39,7 +39,7 @@ App::post('/v1/functions')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', 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, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
|
||||
->param('functionId', '', 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', '', new Text(128), 'Function name. Max length: 128 chars.')
|
||||
->param('execute', [], new ArrayList(new Text(64)), 'An array of strings with execution permissions. By default no user is granted with any execute permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
|
||||
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
|
||||
|
@ -152,6 +152,9 @@ App::get('/v1/functions/:functionId/usage')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'getUsage')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_FUNCTIONS)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d']), 'Date range.', true)
|
||||
->inject('response')
|
||||
|
@ -170,99 +173,62 @@ App::get('/v1/functions/:functionId/usage')
|
|||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$usage = [];
|
||||
if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$period = [
|
||||
'24h' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-24 hours')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('+1 hour')),
|
||||
'group' => '30m',
|
||||
'period' => '30m',
|
||||
'limit' => 48,
|
||||
],
|
||||
'7d' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-7 days')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('now')),
|
||||
'group' => '1d',
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
],
|
||||
'30d' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-30 days')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('now')),
|
||||
'group' => '1d',
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
],
|
||||
'90d' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-90 days')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('now')),
|
||||
'group' => '1d',
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
],
|
||||
];
|
||||
|
||||
$metrics = [
|
||||
"functions.$functionId.executions",
|
||||
"functions.$functionId.failures",
|
||||
"functions.$functionId.compute"
|
||||
];
|
||||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForInternal, $period, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$requestDocs = $dbForInternal->find('stats', [
|
||||
new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $period[$range]['limit'], 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
$client = $register->get('influxdb');
|
||||
|
||||
$executions = [];
|
||||
$failures = [];
|
||||
$compute = [];
|
||||
|
||||
if ($client) {
|
||||
$start = $period[$range]['start']->format(DateTime::RFC3339);
|
||||
$end = $period[$range]['end']->format(DateTime::RFC3339);
|
||||
$database = $client->selectDB('telegraf');
|
||||
|
||||
// Executions
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' AND "functionId"=\''.$function->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$executions[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
|
||||
// Failures
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' AND "functionId"=\''.$function->getId().'\' AND "functionStatus"=\'failed\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$failures[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
|
||||
// Compute
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_time" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' AND "functionId"=\''.$function->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$compute[] = [
|
||||
'value' => round((!empty($point['value'])) ? $point['value'] / 1000 : 0, 2), // minutes
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$response->json([
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
'value' => $requestDoc->getAttribute('value'),
|
||||
'date' => $requestDoc->getAttribute('time'),
|
||||
];
|
||||
}
|
||||
$stats[$metric] = array_reverse($stats[$metric]);
|
||||
}
|
||||
});
|
||||
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'executions' => [
|
||||
'data' => $executions,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $executions)),
|
||||
],
|
||||
'failures' => [
|
||||
'data' => $failures,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $failures)),
|
||||
],
|
||||
'compute' => [
|
||||
'data' => $compute,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $compute)),
|
||||
],
|
||||
'functions.executions' => $stats["functions.$functionId.executions"],
|
||||
'functions.failures' => $stats["functions.$functionId.failures"],
|
||||
'functions.compute' => $stats["functions.$functionId.compute"]
|
||||
]);
|
||||
} else {
|
||||
$response->json([]);
|
||||
}
|
||||
|
||||
$response->dynamic($usage, Response::MODEL_USAGE_FUNCTIONS);
|
||||
});
|
||||
|
||||
App::put('/v1/functions/:functionId')
|
||||
|
|
|
@ -6,10 +6,14 @@ use Appwrite\Network\Validator\CNAME;
|
|||
use Appwrite\Network\Validator\Domain as DomainValidator;
|
||||
use Appwrite\Network\Validator\URL;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Exception;
|
||||
|
@ -19,13 +23,11 @@ use Utopia\Validator\Integer;
|
|||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
|
||||
App::init(function ($project) {
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
||||
if($project->getId() !== 'console') {
|
||||
if ($project->getId() !== 'console') {
|
||||
throw new Exception('Access to this API is forbidden.', 401);
|
||||
}
|
||||
}, ['project'], 'projects');
|
||||
|
@ -40,7 +42,7 @@ App::post('/v1/projects')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->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, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
|
||||
->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('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
|
@ -69,7 +71,7 @@ App::post('/v1/projects')
|
|||
if ($team->isEmpty()) {
|
||||
throw new Exception('Team not found', 404);
|
||||
}
|
||||
|
||||
|
||||
$auth = Config::getParam('auth', []);
|
||||
$auths = ['limit' => 0];
|
||||
foreach ($auth as $index => $method) {
|
||||
|
@ -221,22 +223,25 @@ App::get('/v1/projects/:projectId')
|
|||
});
|
||||
|
||||
App::get('/v1/projects/:projectId/usage')
|
||||
->desc('Get Project')
|
||||
->desc('Get usage stats for a project')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'getUsage')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('register')
|
||||
->action(function ($projectId, $range, $response, $dbForConsole, $projectDB, $register) {
|
||||
->action(function ($projectId, $range, $response, $dbForConsole, $dbForInternal, $register) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
@ -245,172 +250,72 @@ App::get('/v1/projects/:projectId/usage')
|
|||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
|
||||
$period = [
|
||||
'24h' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-24 hours')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('+1 hour')),
|
||||
'group' => '30m',
|
||||
'period' => '30m',
|
||||
'limit' => 48,
|
||||
],
|
||||
'7d' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-7 days')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('now')),
|
||||
'group' => '1d',
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
],
|
||||
'30d' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-30 days')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('now')),
|
||||
'group' => '1d',
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
],
|
||||
'90d' => [
|
||||
'start' => DateTime::createFromFormat('U', \strtotime('-90 days')),
|
||||
'end' => DateTime::createFromFormat('U', \strtotime('now')),
|
||||
'group' => '1d',
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
],
|
||||
];
|
||||
|
||||
$client = $register->get('influxdb');
|
||||
$dbForInternal->setNamespace('project_' . $projectId . '_internal');
|
||||
|
||||
$requests = [];
|
||||
$network = [];
|
||||
$functions = [];
|
||||
$metrics = [
|
||||
'requests',
|
||||
'network',
|
||||
'executions',
|
||||
'users.count',
|
||||
'database.documents.count',
|
||||
'database.collections.count',
|
||||
'storage.total'
|
||||
];
|
||||
|
||||
if ($client) {
|
||||
$start = $period[$range]['start']->format(DateTime::RFC3339);
|
||||
$end = $period[$range]['end']->format(DateTime::RFC3339);
|
||||
$database = $client->selectDB('telegraf');
|
||||
$stats = [];
|
||||
|
||||
// Requests
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_requests_all" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\' AND "project"=\'' . $project->getId() . '\' GROUP BY time(' . $period[$range]['group'] . ') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
Authorization::skip(function() use ($dbForInternal, $period, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$requestDocs = $dbForInternal->find('stats', [
|
||||
new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $period[$range]['limit'], 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
'value' => $requestDoc->getAttribute('value'),
|
||||
'date' => $requestDoc->getAttribute('time'),
|
||||
];
|
||||
}
|
||||
$stats[$metric] = array_reverse($stats[$metric]);
|
||||
}
|
||||
});
|
||||
|
||||
foreach ($points as $point) {
|
||||
$requests[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
|
||||
// Network
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_network_all" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\' AND "project"=\'' . $project->getId() . '\' GROUP BY time(' . $period[$range]['group'] . ') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$network[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
|
||||
// Functions
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\' AND "project"=\'' . $project->getId() . '\' GROUP BY time(' . $period[$range]['group'] . ') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$functions[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$requests = [];
|
||||
$network = [];
|
||||
$functions = [];
|
||||
}
|
||||
|
||||
// Users
|
||||
|
||||
$projectDB->getCollection([
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'filters' => [
|
||||
'$collection=users',
|
||||
],
|
||||
]);
|
||||
|
||||
$usersTotal = $projectDB->getSum();
|
||||
|
||||
// Documents
|
||||
|
||||
$collections = $projectDB->getCollection([
|
||||
'limit' => 100,
|
||||
'offset' => 0,
|
||||
'filters' => [
|
||||
'$collection=collections',
|
||||
],
|
||||
]);
|
||||
|
||||
$collectionsTotal = $projectDB->getSum();
|
||||
|
||||
$documents = [];
|
||||
|
||||
foreach ($collections as $collection) {
|
||||
$result = $projectDB->getCollection([
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'filters' => [
|
||||
'$collection=' . $collection['$id'],
|
||||
],
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'requests' => $stats['requests'],
|
||||
'network' => $stats['network'],
|
||||
'functions' => $stats['executions'],
|
||||
'documents' => $stats['database.documents.count'],
|
||||
'collections' => $stats['database.collections.count'],
|
||||
'users' => $stats['users.count'],
|
||||
'storage' => $stats['storage.total']
|
||||
]);
|
||||
|
||||
$documents[] = ['name' => $collection['name'], 'total' => $projectDB->getSum()];
|
||||
}
|
||||
|
||||
$response->json([
|
||||
'range' => $range,
|
||||
'requests' => [
|
||||
'data' => $requests,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $requests)),
|
||||
],
|
||||
'network' => [
|
||||
'data' => \array_map(function ($value) {return ['value' => \round($value['value'] / 1000000, 2), 'date' => $value['date']];}, $network), // convert bytes to mb
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $network)),
|
||||
],
|
||||
'functions' => [
|
||||
'data' => $functions,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $functions)),
|
||||
],
|
||||
'collections' => [
|
||||
'data' => $collections,
|
||||
'total' => $collectionsTotal,
|
||||
],
|
||||
'documents' => [
|
||||
'data' => $documents,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['total'];
|
||||
}, $documents)),
|
||||
],
|
||||
'users' => [
|
||||
'data' => [],
|
||||
'total' => $usersTotal,
|
||||
],
|
||||
'storage' => [
|
||||
'total' => $projectDB->getCount(
|
||||
[
|
||||
'attribute' => 'sizeOriginal',
|
||||
'filters' => [
|
||||
'$collection=files',
|
||||
],
|
||||
]
|
||||
) +
|
||||
$projectDB->getCount(
|
||||
[
|
||||
'attribute' => 'size',
|
||||
'filters' => [
|
||||
'$collection=tags',
|
||||
],
|
||||
]
|
||||
),
|
||||
],
|
||||
]);
|
||||
$response->dynamic($usage, Response::MODEL_USAGE_PROJECT);
|
||||
});
|
||||
|
||||
App::patch('/v1/projects/:projectId')
|
||||
|
@ -474,7 +379,7 @@ App::patch('/v1/projects/:projectId/service')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), function($element) {return $element['optional'];})), true), 'Service name.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), function ($element) {return $element['optional'];})), true), 'Service name.')
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
|
|
|
@ -10,6 +10,7 @@ use Utopia\Validator\HexColor;
|
|||
use Utopia\Cache\Cache;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Appwrite\ClamAV\Network;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Appwrite\Database\Validator\CustomId;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\UID;
|
||||
|
@ -22,6 +23,7 @@ use Utopia\Image\Image;
|
|||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
App::post('/v1/storage/files')
|
||||
|
@ -38,7 +40,7 @@ App::post('/v1/storage/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('fileId', '', 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, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
|
||||
->param('fileId', '', 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('file', [], new File(), 'Binary file.', false)
|
||||
->param('read', null, new ArrayList(new Text(64)), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new ArrayList(new Text(64)), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
|
@ -54,7 +56,7 @@ App::post('/v1/storage/files')
|
|||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
|
@ -147,11 +149,13 @@ App::post('/v1/storage/files')
|
|||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.create')
|
||||
->setParam('resource', 'storage/files/'.$file->getId())
|
||||
->setParam('resource', 'file/'.$file->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('storage', $sizeActual)
|
||||
->setParam('storage.files.create', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
|
@ -177,9 +181,11 @@ App::get('/v1/storage/files')
|
|||
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
if (!empty($after)) {
|
||||
$afterFile = $dbForInternal->getDocument('files', $after);
|
||||
|
@ -195,6 +201,11 @@ App::get('/v1/storage/files')
|
|||
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'files' => $dbForInternal->find('files', $queries, $limit, $offset, [], [$orderType], $afterFile ?? null),
|
||||
'sum' => $dbForInternal->count('files', $queries, APP_LIMIT_COUNT),
|
||||
|
@ -215,16 +226,21 @@ App::get('/v1/storage/files/:fileId')
|
|||
->param('fileId', '', new UID(), 'File unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($fileId, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($fileId, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$file = $dbForInternal->getDocument('files', $fileId);
|
||||
|
||||
if (empty($file->getId())) {
|
||||
throw new Exception('File not found', 404);
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
$response->dynamic($file, Response::MODEL_FILE);
|
||||
});
|
||||
|
||||
|
@ -255,11 +271,13 @@ App::get('/v1/storage/files/:fileId/preview')
|
|||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForInternal, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $stats */
|
||||
|
||||
$storage = 'files';
|
||||
|
||||
|
@ -372,6 +390,11 @@ App::get('/v1/storage/files/:fileId/preview')
|
|||
|
||||
$cache->save($key, $data);
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
$response
|
||||
->setContentType($outputs[$output])
|
||||
->addHeader('Expires', $date)
|
||||
|
@ -396,9 +419,11 @@ App::get('/v1/storage/files/:fileId/download')
|
|||
->param('fileId', '', new UID(), 'File unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($fileId, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($fileId, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$file = $dbForInternal->getDocument('files', $fileId);
|
||||
|
||||
|
@ -430,6 +455,11 @@ App::get('/v1/storage/files/:fileId/download')
|
|||
|
||||
$source = $compressor->decompress($source);
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
// Response
|
||||
$response
|
||||
->setContentType($file->getAttribute('mimeType'))
|
||||
|
@ -454,9 +484,11 @@ App::get('/v1/storage/files/:fileId/view')
|
|||
->param('fileId', '', new UID(), 'File unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($fileId, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($fileId, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$file = $dbForInternal->getDocument('files', $fileId);
|
||||
$mimes = Config::getParam('storage-mimes');
|
||||
|
@ -496,6 +528,11 @@ App::get('/v1/storage/files/:fileId/view')
|
|||
$output = $compressor->decompress($source);
|
||||
$fileName = $file->getAttribute('name', '');
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
// Response
|
||||
$response
|
||||
->setContentType($contentType)
|
||||
|
@ -526,7 +563,8 @@ App::put('/v1/storage/files/:fileId')
|
|||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($fileId, $read, $write, $response, $dbForInternal, $audits) {
|
||||
->inject('usage')
|
||||
->action(function ($fileId, $read, $write, $response, $dbForInternal, $audits, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
@ -545,7 +583,12 @@ App::put('/v1/storage/files/:fileId')
|
|||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.update')
|
||||
->setParam('resource', 'storage/files/'.$file->getId())
|
||||
->setParam('resource', 'file/'.$file->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.update', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
$response->dynamic($file, Response::MODEL_FILE);
|
||||
|
@ -573,7 +616,7 @@ App::delete('/v1/storage/files/:fileId')
|
|||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$file = $dbForInternal->getDocument('files', $fileId);
|
||||
|
||||
|
@ -591,11 +634,13 @@ App::delete('/v1/storage/files/:fileId')
|
|||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.delete')
|
||||
->setParam('resource', 'storage/files/'.$file->getId())
|
||||
->setParam('resource', 'file/'.$file->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('storage', $file->getAttribute('size', 0) * -1)
|
||||
->setParam('storage.files.delete', 1)
|
||||
->setParam('bucketId', 'default')
|
||||
;
|
||||
|
||||
$events
|
||||
|
@ -603,4 +648,159 @@ App::delete('/v1/storage/files/:fileId')
|
|||
;
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
App::get('/v1/storage/usage')
|
||||
->desc('Get usage stats for storage')
|
||||
->groups(['api', 'storage'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'getUsage')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_STORAGE)
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($range, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$period = [
|
||||
'24h' => [
|
||||
'period' => '30m',
|
||||
'limit' => 48,
|
||||
],
|
||||
'7d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
],
|
||||
'30d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
],
|
||||
'90d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
],
|
||||
];
|
||||
|
||||
$metrics = [
|
||||
"storage.total",
|
||||
"storage.files.count"
|
||||
];
|
||||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForInternal, $period, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$requestDocs = $dbForInternal->find('stats', [
|
||||
new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $period[$range]['limit'], 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
'value' => $requestDoc->getAttribute('value'),
|
||||
'date' => $requestDoc->getAttribute('time'),
|
||||
];
|
||||
}
|
||||
$stats[$metric] = array_reverse($stats[$metric]);
|
||||
}
|
||||
});
|
||||
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'storage' => $stats['storage.total'],
|
||||
'files' => $stats['storage.files.count']
|
||||
]);
|
||||
}
|
||||
|
||||
$response->dynamic($usage, Response::MODEL_USAGE_STORAGE);
|
||||
});
|
||||
|
||||
App::get('/v1/storage/:bucketId/usage')
|
||||
->desc('Get usage stats for a storage bucket')
|
||||
->groups(['api', 'storage'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'getBucketUsage')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_BUCKETS)
|
||||
->param('bucketId', '', new UID(), 'Bucket unique ID.')
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($bucketId, $range, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
// TODO: Check if the storage bucket exists else throw 404
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$period = [
|
||||
'24h' => [
|
||||
'period' => '30m',
|
||||
'limit' => 48,
|
||||
],
|
||||
'7d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
],
|
||||
'30d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
],
|
||||
'90d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
],
|
||||
];
|
||||
|
||||
$metrics = [
|
||||
"storage.buckets.$bucketId.files.count",
|
||||
"storage.buckets.$bucketId.files.create",
|
||||
"storage.buckets.$bucketId.files.read",
|
||||
"storage.buckets.$bucketId.files.update",
|
||||
"storage.buckets.$bucketId.files.delete"
|
||||
];
|
||||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForInternal, $period, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$requestDocs = $dbForInternal->find('stats', [
|
||||
new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $period[$range]['limit'], 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
'value' => $requestDoc->getAttribute('value'),
|
||||
'date' => $requestDoc->getAttribute('time'),
|
||||
];
|
||||
}
|
||||
$stats[$metric] = array_reverse($stats[$metric]);
|
||||
}
|
||||
});
|
||||
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'files.count' => $stats["storage.buckets.$bucketId.files.count"],
|
||||
'files.create' => $stats["storage.buckets.$bucketId.files.create"],
|
||||
'files.read' => $stats["storage.buckets.$bucketId.files.read"],
|
||||
'files.update' => $stats["storage.buckets.$bucketId.files.update"],
|
||||
'files.delete' => $stats["storage.buckets.$bucketId.files.delete"]
|
||||
]);
|
||||
}
|
||||
|
||||
$response->dynamic($usage, Response::MODEL_USAGE_BUCKETS);
|
||||
});
|
|
@ -33,7 +33,7 @@ App::post('/v1/teams')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TEAM)
|
||||
->param('teamId', '', 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, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
|
||||
->param('teamId', '', 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), 'Team name. Max length: 128 chars.')
|
||||
->param('roles', ['owner'], new ArrayList(new Key()), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.', true)
|
||||
->inject('response')
|
||||
|
@ -408,7 +408,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
$audits
|
||||
->setParam('userId', $invitee->getId())
|
||||
->setParam('event', 'teams.memberships.create')
|
||||
->setParam('resource', 'teams/'.$teamId)
|
||||
->setParam('resource', 'team/'.$teamId)
|
||||
;
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
|
@ -570,7 +570,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'teams.memberships.update')
|
||||
->setParam('resource', 'teams/'.$teamId)
|
||||
->setParam('resource', 'team/'.$teamId)
|
||||
;
|
||||
|
||||
$response->dynamic($membership, Response::MODEL_MEMBERSHIP);
|
||||
|
@ -695,7 +695,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'teams.memberships.update.status')
|
||||
->setParam('resource', 'teams/'.$teamId)
|
||||
->setParam('resource', 'team/'.$teamId)
|
||||
;
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
|
@ -788,7 +788,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
|||
$audits
|
||||
->setParam('userId', $membership->getAttribute('userId'))
|
||||
->setParam('event', 'teams.memberships.delete')
|
||||
->setParam('resource', 'teams/'.$teamId)
|
||||
->setParam('resource', 'team/'.$teamId)
|
||||
;
|
||||
|
||||
$events
|
||||
|
|
|
@ -17,7 +17,10 @@ use Utopia\Database\Exception\Duplicate;
|
|||
use Utopia\Database\Validator\UID;
|
||||
use DeviceDetector\DeviceDetector;
|
||||
use Appwrite\Database\Validator\CustomId;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
App::post('/v1/users')
|
||||
->desc('Create User')
|
||||
|
@ -31,15 +34,17 @@ App::post('/v1/users')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->param('userId', '', 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, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
|
||||
->param('userId', '', 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('email', '', new Email(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $email, $password, $name, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $email, $password, $name, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$email = \strtolower($email);
|
||||
|
||||
|
@ -67,6 +72,10 @@ App::post('/v1/users')
|
|||
throw new Exception('Account already exists', 409);
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.create', 1)
|
||||
;
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
@ -89,9 +98,11 @@ App::get('/v1/users')
|
|||
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
if (!empty($after)) {
|
||||
$afterUser = $dbForInternal->getDocument('users', $after);
|
||||
|
@ -107,12 +118,13 @@ App::get('/v1/users')
|
|||
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
|
||||
}
|
||||
|
||||
$results = $dbForInternal->find('users', $queries, $limit, $offset, ['_id'], [$orderType]);
|
||||
$sum = $dbForInternal->count('users', $queries, APP_LIMIT_COUNT);
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'users' => $results,
|
||||
'sum' => $sum,
|
||||
'users' => $dbForInternal->find('users', [], $limit, $offset, [], [$orderType], $afterUser ?? null),
|
||||
'sum' => $dbForInternal->count('users', [], APP_LIMIT_COUNT),
|
||||
]), Response::MODEL_USER_LIST);
|
||||
});
|
||||
|
||||
|
@ -130,9 +142,11 @@ App::get('/v1/users/:userId')
|
|||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -140,6 +154,9 @@ App::get('/v1/users/:userId')
|
|||
throw new Exception('User not found', 404);
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -157,9 +174,11 @@ App::get('/v1/users/:userId/prefs')
|
|||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -169,6 +188,9 @@ App::get('/v1/users/:userId/prefs')
|
|||
|
||||
$prefs = $user->getAttribute('prefs', new \stdClass());
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
|
||||
});
|
||||
|
||||
|
@ -187,10 +209,12 @@ App::get('/v1/users/:userId/sessions')
|
|||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('locale')
|
||||
->action(function ($userId, $response, $dbForInternal, $locale) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForInternal, $locale, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -210,6 +234,9 @@ App::get('/v1/users/:userId/sessions')
|
|||
$sessions[$key] = $session;
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic(new Document([
|
||||
'sessions' => $sessions,
|
||||
'sum' => count($sessions),
|
||||
|
@ -232,12 +259,14 @@ App::get('/v1/users/:userId/logs')
|
|||
->inject('dbForInternal')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function ($userId, $response, $dbForInternal, $locale, $geodb) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForInternal, $locale, $geodb, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -319,6 +348,9 @@ App::get('/v1/users/:userId/logs')
|
|||
}
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.read', 1)
|
||||
;
|
||||
$response->dynamic(new Document(['logs' => $output]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
|
@ -338,9 +370,11 @@ App::patch('/v1/users/:userId/status')
|
|||
->param('status', null, new Boolean(true), 'User Status. To activate the user pass `true` and to block the user pass `false`')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $status, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $status, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -350,6 +384,9 @@ App::patch('/v1/users/:userId/status')
|
|||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('status', (bool) $status));
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -369,9 +406,11 @@ App::patch('/v1/users/:userId/verification')
|
|||
->param('emailVerification', false, new Boolean(), 'User Email Verification Status.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $emailVerification, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $emailVerification, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -381,6 +420,132 @@ App::patch('/v1/users/:userId/verification')
|
|||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification));
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
App::patch('/v1/users/:userId/name')
|
||||
->desc('Update Name')
|
||||
->groups(['api', 'users'])
|
||||
->label('event', 'users.update.name')
|
||||
->label('scope', 'users.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'users')
|
||||
->label('sdk.method', 'updateName')
|
||||
->label('sdk.description', '/docs/references/users/update-user-name.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($userId, $name, $response, $dbForInternal, $audits) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404);
|
||||
}
|
||||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('name', $name));
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'users.update.name')
|
||||
->setParam('resource', 'user/'.$user->getId())
|
||||
;
|
||||
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
App::patch('/v1/users/:userId/password')
|
||||
->desc('Update Password')
|
||||
->groups(['api', 'users'])
|
||||
->label('event', 'users.update.password')
|
||||
->label('scope', 'users.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'users')
|
||||
->label('sdk.method', 'updatePassword')
|
||||
->label('sdk.description', '/docs/references/users/update-user-password.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->param('password', '', new Password(), 'New user password. Must be between 6 to 32 chars.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($userId, $password, $response, $dbForInternal, $audits) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404);
|
||||
}
|
||||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('password', Auth::passwordHash($password))
|
||||
->setAttribute('passwordUpdate', \time()));
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'users.update.password')
|
||||
->setParam('resource', 'user/'.$user->getId())
|
||||
;
|
||||
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
App::patch('/v1/users/:userId/email')
|
||||
->desc('Update Email')
|
||||
->groups(['api', 'users'])
|
||||
->label('event', 'users.update.email')
|
||||
->label('scope', 'users.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'users')
|
||||
->label('sdk.method', 'updateEmail')
|
||||
->label('sdk.description', '/docs/references/users/update-user-email.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($userId, $email, $response, $dbForInternal, $audits) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404);
|
||||
}
|
||||
|
||||
$email = \strtolower($email);
|
||||
try {
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('email', $email));
|
||||
} catch(Duplicate $th) {
|
||||
throw new Exception('Email already exists', 409);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.update.email')
|
||||
->setParam('resource', 'user/'.$user->getId())
|
||||
;
|
||||
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
|
@ -400,9 +565,11 @@ App::patch('/v1/users/:userId/prefs')
|
|||
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $prefs, $response, $dbForInternal) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $prefs, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -412,6 +579,9 @@ App::patch('/v1/users/:userId/prefs')
|
|||
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
;
|
||||
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
|
||||
});
|
||||
|
||||
|
@ -431,10 +601,12 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('events')
|
||||
->action(function ($userId, $sessionId, $response, $dbForInternal, $events) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $sessionId, $response, $dbForInternal, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -461,6 +633,11 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
}
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
->setParam('users.sessions.delete', 1)
|
||||
;
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
@ -479,10 +656,12 @@ App::delete('/v1/users/:userId/sessions')
|
|||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('events')
|
||||
->action(function ($userId, $response, $dbForInternal, $events) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForInternal, $events, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -502,6 +681,10 @@ App::delete('/v1/users/:userId/sessions')
|
|||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
->setParam('users.sessions.delete', 1)
|
||||
;
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
@ -521,11 +704,13 @@ App::delete('/v1/users/:userId')
|
|||
->inject('dbForInternal')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function ($userId, $response, $dbForInternal, $events, $deletes) {
|
||||
->inject('usage')
|
||||
->action(function ($userId, $response, $dbForInternal, $events, $deletes, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
|
@ -546,5 +731,96 @@ App::delete('/v1/users/:userId')
|
|||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.delete', 1)
|
||||
;
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
App::get('/v1/users/usage')
|
||||
->desc('Get usage stats for the users API')
|
||||
->groups(['api', 'users'])
|
||||
->label('scope', 'users.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'users')
|
||||
->label('sdk.method', 'getUsage')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_USERS)
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(function($value) { return "oauth-".$value; }, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('register')
|
||||
->action(function ($range, $provider, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$period = [
|
||||
'24h' => [
|
||||
'period' => '30m',
|
||||
'limit' => 48,
|
||||
],
|
||||
'7d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
],
|
||||
'30d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
],
|
||||
'90d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
],
|
||||
];
|
||||
|
||||
$metrics = [
|
||||
"users.count",
|
||||
"users.create",
|
||||
"users.read",
|
||||
"users.update",
|
||||
"users.delete",
|
||||
"users.sessions.create",
|
||||
"users.sessions.$provider.create",
|
||||
"users.sessions.delete"
|
||||
];
|
||||
|
||||
$stats = [];
|
||||
|
||||
Authorization::skip(function() use ($dbForInternal, $period, $range, $metrics, &$stats) {
|
||||
foreach ($metrics as $metric) {
|
||||
$requestDocs = $dbForInternal->find('stats', [
|
||||
new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $period[$range]['limit'], 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
'value' => $requestDoc->getAttribute('value'),
|
||||
'date' => $requestDoc->getAttribute('time'),
|
||||
];
|
||||
}
|
||||
$stats[$metric] = array_reverse($stats[$metric]);
|
||||
}
|
||||
});
|
||||
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'users.count' => $stats["users.count"],
|
||||
'users.create' => $stats["users.create"],
|
||||
'users.read' => $stats["users.read"],
|
||||
'users.update' => $stats["users.update"],
|
||||
'users.delete' => $stats["users.delete"],
|
||||
'sessions.create' => $stats["users.sessions.create"],
|
||||
'sessions.provider.create' => $stats["users.sessions.$provider.create"],
|
||||
'sessions.delete' => $stats["users.sessions.delete"]
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
$response->dynamic($usage, Response::MODEL_USAGE_USERS);
|
||||
});
|
|
@ -319,7 +319,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
|
|||
|
||||
if($route) {
|
||||
Console::error('[Error] Method: '.$route->getMethod());
|
||||
Console::error('[Error] URL: '.$route->getURL());
|
||||
Console::error('[Error] URL: '.$route->getPath());
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
|
|
|
@ -518,7 +518,7 @@ App::shutdown(function($utopia, $response, $request) {
|
|||
throw new Exception('Failed to read results', 500);
|
||||
}
|
||||
|
||||
$result[$route->getMethod() . ':' . $route->getURL()] = true;
|
||||
$result[$route->getMethod() . ':' . $route->getPath()] = true;
|
||||
|
||||
$tests = \array_merge($tests, $result);
|
||||
|
||||
|
@ -526,5 +526,5 @@ App::shutdown(function($utopia, $response, $request) {
|
|||
throw new Exception('Failed to save results', 500);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getURL() . ':passed']), Response::MODEL_MOCK);
|
||||
$response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK);
|
||||
}, ['utopia', 'response', 'request'], 'mock');
|
|
@ -41,7 +41,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname().$route->getURL())
|
||||
->setParam('{url}', $request->getHostname().$route->getPath())
|
||||
;
|
||||
|
||||
// TODO make sure we get array here
|
||||
|
@ -104,6 +104,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
->setParam('httpRequest', 1)
|
||||
->setParam('httpUrl', $request->getHostname().$request->getURI())
|
||||
->setParam('httpMethod', $request->getMethod())
|
||||
->setParam('httpPath', $route->getPath())
|
||||
->setParam('networkRequestSize', 0)
|
||||
->setParam('networkResponseSize', 0)
|
||||
->setParam('storage', 0)
|
||||
|
|
|
@ -387,11 +387,10 @@ App::get('/specs/:format')
|
|||
}
|
||||
|
||||
$routes[] = $route;
|
||||
$model = $response->getModel($route->getLabel('sdk.response.model', 'none'));
|
||||
|
||||
if($model) {
|
||||
$models[$model->getType()] = $model;
|
||||
}
|
||||
$modelLabel = $route->getLabel('sdk.response.model', 'none');
|
||||
$model = \is_array($modelLabel) ? \array_map(function($m) use($response) {
|
||||
return $response->getModel($m);
|
||||
}, $modelLabel) : $response->getModel($modelLabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
188
app/init.php
188
app/init.php
|
@ -17,13 +17,13 @@ ini_set('display_startup_errors', 1);
|
|||
ini_set('default_socket_timeout', -1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
use Appwrite\Extend\PDO;
|
||||
use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Database as DatabaseOld;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\IP;
|
||||
|
@ -40,8 +40,8 @@ use PHPMailer\PHPMailer\PHPMailer;
|
|||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Document as Document2;
|
||||
use Utopia\Database\Database as Database2;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Structure;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Range;
|
||||
|
@ -49,6 +49,7 @@ use Swoole\Database\PDOConfig;
|
|||
use Swoole\Database\PDOPool;
|
||||
use Swoole\Database\RedisConfig;
|
||||
use Swoole\Database\RedisPool;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
const APP_NAME = 'Appwrite';
|
||||
const APP_DOMAIN = 'appwrite.io';
|
||||
|
@ -61,7 +62,12 @@ const APP_PAGING_LIMIT = 12;
|
|||
const APP_LIMIT_COUNT = 5000;
|
||||
const APP_LIMIT_USERS = 10000;
|
||||
const APP_CACHE_BUSTER = 151;
|
||||
const APP_VERSION_STABLE = '0.10.0';
|
||||
const APP_VERSION_STABLE = '0.9.4';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
const APP_DATABASE_ATTRIBUTE_URL = 'url';
|
||||
const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange';
|
||||
const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange';
|
||||
const APP_STORAGE_UPLOADS = '/storage/uploads';
|
||||
const APP_STORAGE_FUNCTIONS = '/storage/functions';
|
||||
const APP_STORAGE_CACHE = '/storage/cache';
|
||||
|
@ -88,6 +94,7 @@ const DELETE_TYPE_EXECUTIONS = 'executions';
|
|||
const DELETE_TYPE_AUDIT = 'audit';
|
||||
const DELETE_TYPE_ABUSE = 'abuse';
|
||||
const DELETE_TYPE_CERTIFICATES = 'certificates';
|
||||
const DELETE_TYPE_USAGE = 'usage';
|
||||
// Mail Worker Types
|
||||
const MAIL_TYPE_VERIFICATION = 'verification';
|
||||
const MAIL_TYPE_RECOVERY = 'recovery';
|
||||
|
@ -138,10 +145,11 @@ if(!empty($user) || !empty($pass)) {
|
|||
} else {
|
||||
Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* DB Filters
|
||||
* Old DB Filters
|
||||
*/
|
||||
Database::addFilter('json',
|
||||
DatabaseOld::addFilter('json',
|
||||
function($value) {
|
||||
if(!is_array($value)) {
|
||||
return $value;
|
||||
|
@ -153,7 +161,7 @@ Database::addFilter('json',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('encrypt',
|
||||
DatabaseOld::addFilter('encrypt',
|
||||
function($value) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
|
@ -175,7 +183,68 @@ Database::addFilter('encrypt',
|
|||
}
|
||||
);
|
||||
|
||||
Database2::addFilter('encrypt',
|
||||
/**
|
||||
* New DB Filters
|
||||
*/
|
||||
Database::addFilter('casting',
|
||||
function($value) {
|
||||
return json_encode(['value' => $value]);
|
||||
},
|
||||
function($value) {
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
return json_decode($value, true)['value'];
|
||||
}
|
||||
);
|
||||
|
||||
Database::addFilter('range',
|
||||
function($value, Document $attribute) {
|
||||
if ($attribute->isSet('min')) {
|
||||
$attribute->removeAttribute('min');
|
||||
}
|
||||
if ($attribute->isSet('max')) {
|
||||
$attribute->removeAttribute('max');
|
||||
}
|
||||
return $value;
|
||||
},
|
||||
function($value, Document $attribute) {
|
||||
$formatOptions = json_decode($attribute->getAttribute('formatOptions', []), true);
|
||||
if (isset($formatOptions['min']) || isset($formatOptions['max'])) {
|
||||
$attribute
|
||||
->setAttribute('min', $formatOptions['min'])
|
||||
->setAttribute('max', $formatOptions['max'])
|
||||
;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryAttributes',
|
||||
function($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('attributes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], 100, 0, []);
|
||||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryIndexes',
|
||||
function($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('indexes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], 100, 0, []);
|
||||
}
|
||||
);
|
||||
|
||||
Database::addFilter('encrypt',
|
||||
function($value) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
|
@ -196,37 +265,32 @@ Database2::addFilter('encrypt',
|
|||
}
|
||||
);
|
||||
|
||||
Structure::addFormat('email', function() {
|
||||
/**
|
||||
* DB Formats
|
||||
*/
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_EMAIL, function() {
|
||||
return new Email();
|
||||
}, Database2::VAR_STRING);
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat('ip', function() {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_IP, function() {
|
||||
return new IP();
|
||||
}, Database2::VAR_STRING);
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat('url', function() {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function() {
|
||||
return new URL();
|
||||
}, Database2::VAR_STRING);
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
Structure::addFormat('int-range', function($attribute) {
|
||||
// Format encoded as json string containing name and relevant options
|
||||
// E.g. Range: $format = json_encode(['name'=>$name, 'min'=>$min, 'max'=>$max]);
|
||||
$format = json_decode($attribute['format'], true);
|
||||
$min = $format['min'] ?? -INF;
|
||||
$max = $format['max'] ?? INF;
|
||||
$type = $attribute['type'];
|
||||
return new Range($min, $max, $type);
|
||||
}, Database2::VAR_INTEGER);
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
return new Range($min, $max, Range::TYPE_INTEGER);
|
||||
}, Database::VAR_INTEGER);
|
||||
|
||||
Structure::addFormat('float-range', function($attribute) {
|
||||
// Format encoded as json string containing name and relevant options
|
||||
// E.g. Range: $format = json_encode(['name'=>$name, 'min'=>$min, 'max'=>$max]);
|
||||
$format = json_decode($attribute['format'], true);
|
||||
$min = $format['min'] ?? -INF;
|
||||
$max = $format['max'] ?? INF;
|
||||
$type = $attribute['type'] ?? '';
|
||||
return new Range($min, $max, $type);
|
||||
}, Database2::VAR_FLOAT);
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
return new Range($min, $max, Range::TYPE_FLOAT);
|
||||
}, Database::VAR_FLOAT);
|
||||
|
||||
/*
|
||||
* Registry
|
||||
|
@ -238,7 +302,6 @@ $register->set('dbPool', function () { // Register DB connection
|
|||
$dbPass = App::getEnv('_APP_DB_PASS', '');
|
||||
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
|
||||
|
||||
|
||||
$pool = new PDOPool((new PDOConfig())
|
||||
->withHost($dbHost)
|
||||
->withPort($dbPort)
|
||||
|
@ -246,6 +309,9 @@ $register->set('dbPool', function () { // Register DB connection
|
|||
->withCharset('utf8mb4')
|
||||
->withUsername($dbUser)
|
||||
->withPassword($dbPass)
|
||||
->withOptions([
|
||||
PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed
|
||||
])
|
||||
, 16);
|
||||
|
||||
return $pool;
|
||||
|
@ -292,7 +358,6 @@ $register->set('statsd', function () { // Register DB connection
|
|||
|
||||
return $statsd;
|
||||
});
|
||||
|
||||
$register->set('smtp', function () {
|
||||
$mail = new PHPMailer(true);
|
||||
|
||||
|
@ -324,6 +389,29 @@ $register->set('smtp', function () {
|
|||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__.'/db/DBIP/dbip-country-lite-2021-06.mmdb');
|
||||
});
|
||||
$register->set('db', function () { // This is usually for our workers or CLI commands scope
|
||||
$dbHost = App::getEnv('_APP_DB_HOST', '');
|
||||
$dbUser = App::getEnv('_APP_DB_USER', '');
|
||||
$dbPass = App::getEnv('_APP_DB_PASS', '');
|
||||
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
|
||||
|
||||
$pdo = new PDO("mysql:host={$dbHost};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array(
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
));
|
||||
|
||||
return $pdo;
|
||||
});
|
||||
$register->set('cache', function () { // This is usually for our workers or CLI commands scope
|
||||
$redis = new Redis();
|
||||
$redis->pconnect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
|
||||
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
|
||||
|
||||
return $redis;
|
||||
});
|
||||
|
||||
/*
|
||||
* Localization
|
||||
|
@ -440,8 +528,8 @@ App::setResource('database', function($register) {
|
|||
|
||||
// Test Mock
|
||||
App::setResource('clients', function($request, $console, $project) {
|
||||
$console->setAttribute('platforms', [ // Allways allow current host
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
$console->setAttribute('platforms', [ // Always allow current host
|
||||
'$collection' => 'platforms',
|
||||
'name' => 'Current Host',
|
||||
'type' => 'web',
|
||||
'hostname' => $request->getHostname(),
|
||||
|
@ -509,7 +597,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
|
||||
if (APP_MODE_ADMIN !== $mode) {
|
||||
if ($project->isEmpty()) {
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
$user = new Document(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
else {
|
||||
$user = $dbForInternal->getDocument('users', Auth::$unique);
|
||||
|
@ -521,14 +609,14 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
|
||||
if ($user->isEmpty() // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)) { // Validate user has valid login token
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
$user = new Document(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
|
||||
if (APP_MODE_ADMIN === $mode) {
|
||||
if ($user->find('teamId', $project->getAttribute('teamId'), 'memberships')) {
|
||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
|
||||
} else {
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
$user = new Document(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,7 +639,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
|||
}
|
||||
|
||||
if (empty($user->find('$id', $jwtSessionId, 'sessions'))) { // Match JWT to active token
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
$user = new Document(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,7 +668,7 @@ App::setResource('project', function($dbForConsole, $request, $console) {
|
|||
}, ['dbForConsole', 'request', 'console']);
|
||||
|
||||
App::setResource('console', function() {
|
||||
return new Document2([
|
||||
return new Document([
|
||||
'$id' => 'console',
|
||||
'name' => 'Appwrite',
|
||||
'$collection' => 'projects',
|
||||
|
@ -591,19 +679,19 @@ App::setResource('console', function() {
|
|||
'keys' => [],
|
||||
'platforms' => [
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'$collection' => 'platforms',
|
||||
'name' => 'Production',
|
||||
'type' => 'web',
|
||||
'hostname' => 'appwrite.io',
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'$collection' => 'platforms',
|
||||
'name' => 'Development',
|
||||
'type' => 'web',
|
||||
'hostname' => 'appwrite.test',
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'$collection' => 'platforms',
|
||||
'name' => 'Localhost',
|
||||
'type' => 'web',
|
||||
'hostname' => 'localhost',
|
||||
|
@ -624,7 +712,7 @@ App::setResource('console', function() {
|
|||
}, []);
|
||||
|
||||
App::setResource('consoleDB', function($db, $cache) {
|
||||
$consoleDB = new Database();
|
||||
$consoleDB = new DatabaseOld();
|
||||
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
$consoleDB->setNamespace('app_console'); // Should be replaced with param if we want to have parent projects
|
||||
$consoleDB->setMocks(Config::getParam('collections', []));
|
||||
|
@ -633,7 +721,7 @@ App::setResource('consoleDB', function($db, $cache) {
|
|||
}, ['db', 'cache']);
|
||||
|
||||
App::setResource('projectDB', function($db, $cache, $project) {
|
||||
$projectDB = new Database();
|
||||
$projectDB = new DatabaseOld();
|
||||
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
$projectDB->setNamespace('app_'.$project->getId());
|
||||
$projectDB->setMocks(Config::getParam('collections', []));
|
||||
|
@ -644,7 +732,7 @@ App::setResource('projectDB', function($db, $cache, $project) {
|
|||
App::setResource('dbForInternal', function($db, $cache, $project) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database2(new MariaDB($db), $cache);
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setNamespace('project_'.$project->getId().'_internal');
|
||||
|
||||
return $database;
|
||||
|
@ -653,7 +741,7 @@ App::setResource('dbForInternal', function($db, $cache, $project) {
|
|||
App::setResource('dbForExternal', function($db, $cache, $project) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database2(new MariaDB($db), $cache);
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setNamespace('project_'.$project->getId().'_external');
|
||||
|
||||
return $database;
|
||||
|
@ -662,7 +750,7 @@ App::setResource('dbForExternal', function($db, $cache, $project) {
|
|||
App::setResource('dbForConsole', function($db, $cache) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database2(new MariaDB($db), $cache);
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setNamespace('project_console_internal');
|
||||
|
||||
return $database;
|
||||
|
|
|
@ -39,17 +39,29 @@ $cli
|
|||
]);
|
||||
}
|
||||
|
||||
function notifyDeleteUsageStats(int $interval30m, int $interval1d)
|
||||
{
|
||||
Resque::enqueue(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME, [
|
||||
'type' => DELETE_TYPE_USAGE,
|
||||
'timestamp1d' => time() - $interval1d,
|
||||
'timestamp30m' => time() - $interval30m,
|
||||
]);
|
||||
}
|
||||
|
||||
// # of days in seconds (1 day = 86400s)
|
||||
$interval = (int) App::getEnv('_APP_MAINTENANCE_INTERVAL', '86400');
|
||||
$executionLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', '1209600');
|
||||
$auditLogRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', '1209600');
|
||||
$abuseLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', '86400');
|
||||
$usageStatsRetention30m = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_30M', '129600');//36 hours
|
||||
$usageStatsRetention1d = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_1D', '8640000'); // 100 days
|
||||
|
||||
Console::loop(function() use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention){
|
||||
Console::loop(function() use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d) {
|
||||
$time = date('d-m-Y H:i:s', time());
|
||||
Console::info("[{$time}] Notifying deletes workers every {$interval} seconds");
|
||||
notifyDeleteExecutionLogs($executionLogsRetention);
|
||||
notifyDeleteAbuseLogs($abuseLogsRetention);
|
||||
notifyDeleteAuditLogs($auditLogRetention);
|
||||
notifyDeleteUsageStats($usageStatsRetention30m, $usageStatsRetention1d);
|
||||
}, $interval);
|
||||
});
|
586
app/tasks/usage.php
Normal file
586
app/tasks/usage.php
Normal file
|
@ -0,0 +1,586 @@
|
|||
<?php
|
||||
|
||||
global $cli, $register;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Redis;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
/**
|
||||
* Metrics We collect
|
||||
*
|
||||
* General
|
||||
*
|
||||
* requests
|
||||
* network
|
||||
* executions
|
||||
*
|
||||
* Database
|
||||
*
|
||||
* database.collections.create
|
||||
* database.collections.read
|
||||
* database.collections.update
|
||||
* database.collections.delete
|
||||
* database.documents.create
|
||||
* database.documents.read
|
||||
* database.documents.update
|
||||
* database.documents.delete
|
||||
* database.collections.{collectionId}.documents.create
|
||||
* database.collections.{collectionId}.documents.read
|
||||
* database.collections.{collectionId}.documents.update
|
||||
* database.collections.{collectionId}.documents.delete
|
||||
*
|
||||
* Storage
|
||||
*
|
||||
* storage.buckets.{bucketId}.files.create
|
||||
* storage.buckets.{bucketId}.files.read
|
||||
* storage.buckets.{bucketId}.files.update
|
||||
* storage.buckets.{bucketId}.files.delete
|
||||
*
|
||||
* Users
|
||||
*
|
||||
* users.create
|
||||
* users.read
|
||||
* users.update
|
||||
* users.delete
|
||||
* users.sessions.create
|
||||
* users.sessions.{provider}.create
|
||||
* users.sessions.delete
|
||||
*
|
||||
* Functions
|
||||
*
|
||||
* functions.{functionId}.executions
|
||||
* functions.{functionId}.failures
|
||||
* functions.{functionId}.compute
|
||||
*
|
||||
* Counters
|
||||
*
|
||||
* users.count
|
||||
* storage.files.count
|
||||
* database.collections.count
|
||||
* database.documents.count
|
||||
* database.collections.{collectionId}.documents.count
|
||||
*
|
||||
* Totals
|
||||
*
|
||||
* storage.total
|
||||
*
|
||||
*/
|
||||
|
||||
$cli
|
||||
->task('usage')
|
||||
->desc('Schedules syncing data from influxdb to Appwrite console db')
|
||||
->action(function () use ($register) {
|
||||
Console::title('Usage Aggregation V1');
|
||||
Console::success(APP_NAME . ' usage aggregation process v1 has started');
|
||||
|
||||
$interval = (int) App::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', '30'); // 30 seconds (by default)
|
||||
$periods = [
|
||||
[
|
||||
'key' => '30m',
|
||||
'startTime' => '-24 hours',
|
||||
],
|
||||
[
|
||||
'key' => '1d',
|
||||
'startTime' => '-90 days',
|
||||
],
|
||||
];
|
||||
|
||||
// all the metrics that we are collecting at the moment
|
||||
$globalMetrics = [
|
||||
'requests' => [
|
||||
'table' => 'appwrite_usage_requests_all',
|
||||
],
|
||||
'network' => [
|
||||
'table' => 'appwrite_usage_network_all',
|
||||
],
|
||||
'executions' => [
|
||||
'table' => 'appwrite_usage_executions_all',
|
||||
],
|
||||
'database.collections.create' => [
|
||||
'table' => 'appwrite_usage_database_collections_create',
|
||||
],
|
||||
'database.collections.read' => [
|
||||
'table' => 'appwrite_usage_database_collections_read',
|
||||
],
|
||||
'database.collections.update' => [
|
||||
'table' => 'appwrite_usage_database_collections_update',
|
||||
],
|
||||
'database.collections.delete' => [
|
||||
'table' => 'appwrite_usage_database_collections_delete',
|
||||
],
|
||||
'database.documents.create' => [
|
||||
'table' => 'appwrite_usage_database_documents_create',
|
||||
],
|
||||
'database.documents.read' => [
|
||||
'table' => 'appwrite_usage_database_documents_read',
|
||||
],
|
||||
'database.documents.update' => [
|
||||
'table' => 'appwrite_usage_database_documents_update',
|
||||
],
|
||||
'database.documents.delete' => [
|
||||
'table' => 'appwrite_usage_database_documents_delete',
|
||||
],
|
||||
'database.collections.collectionId.documents.create' => [
|
||||
'table' => 'appwrite_usage_database_documents_create',
|
||||
'groupBy' => 'collectionId',
|
||||
],
|
||||
'database.collections.collectionId.documents.read' => [
|
||||
'table' => 'appwrite_usage_database_documents_read',
|
||||
'groupBy' => 'collectionId',
|
||||
],
|
||||
'database.collections.collectionId.documents.update' => [
|
||||
'table' => 'appwrite_usage_database_documents_update',
|
||||
'groupBy' => 'collectionId',
|
||||
],
|
||||
'database.collections.collectionId.documents.delete' => [
|
||||
'table' => 'appwrite_usage_database_documents_delete',
|
||||
'groupBy' => 'collectionId',
|
||||
],
|
||||
'storage.buckets.bucketId.files.create' => [
|
||||
'table' => 'appwrite_usage_storage_files_create',
|
||||
'groupBy' => 'bucketId',
|
||||
],
|
||||
'storage.buckets.bucketId.files.read' => [
|
||||
'table' => 'appwrite_usage_storage_files_read',
|
||||
'groupBy' => 'bucketId',
|
||||
],
|
||||
'storage.buckets.bucketId.files.update' => [
|
||||
'table' => 'appwrite_usage_storage_files_update',
|
||||
'groupBy' => 'bucketId',
|
||||
],
|
||||
'storage.buckets.bucketId.files.delete' => [
|
||||
'table' => 'appwrite_usage_storage_files_delete',
|
||||
'groupBy' => 'bucketId',
|
||||
],
|
||||
'users.create' => [
|
||||
'table' => 'appwrite_usage_users_create',
|
||||
],
|
||||
'users.read' => [
|
||||
'table' => 'appwrite_usage_users_read',
|
||||
],
|
||||
'users.update' => [
|
||||
'table' => 'appwrite_usage_users_update',
|
||||
],
|
||||
'users.delete' => [
|
||||
'table' => 'appwrite_usage_users_delete',
|
||||
],
|
||||
'users.sessions.create' => [
|
||||
'table' => 'appwrite_usage_users_sessions_create',
|
||||
],
|
||||
'users.sessions.provider.create' => [
|
||||
'table' => 'appwrite_usage_users_sessions_create',
|
||||
'groupBy' => 'provider',
|
||||
],
|
||||
'users.sessions.delete' => [
|
||||
'table' => 'appwrite_usage_users_sessions_delete',
|
||||
],
|
||||
'functions.functionId.executions' => [
|
||||
'table' => 'appwrite_usage_executions_all',
|
||||
'groupBy' => 'functionId',
|
||||
],
|
||||
'functions.functionId.compute' => [
|
||||
'table' => 'appwrite_usage_executions_time',
|
||||
'groupBy' => 'functionId',
|
||||
],
|
||||
'functions.functionId.failures' => [
|
||||
'table' => 'appwrite_usage_executions_all',
|
||||
'groupBy' => 'functionId',
|
||||
'filters' => [
|
||||
'functionStatus' => 'failed',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// TODO Maybe move this to the setResource method, and reuse in the http.php file
|
||||
$attempts = 0;
|
||||
$max = 10;
|
||||
$sleep = 1;
|
||||
|
||||
do { // connect to db
|
||||
try {
|
||||
$attempts++;
|
||||
$db = $register->get('db');
|
||||
$redis = $register->get('cache');
|
||||
break; // leave the do-while if successful
|
||||
} catch (\Exception $e) {
|
||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
} while ($attempts < $max);
|
||||
|
||||
// TODO use inject
|
||||
$cacheAdapter = new Cache(new Redis($redis));
|
||||
$dbForProject = new Database(new MariaDB($db), $cacheAdapter);
|
||||
$dbForConsole = new Database(new MariaDB($db), $cacheAdapter);
|
||||
$dbForConsole->setNamespace('project_console_internal');
|
||||
|
||||
$latestTime = [];
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$iterations = 0;
|
||||
Console::loop(function () use ($interval, $register, $dbForProject, $dbForConsole, $globalMetrics, $periods, &$latestTime, &$iterations) {
|
||||
$now = date('d-m-Y H:i:s', time());
|
||||
Console::info("[{$now}] Aggregating usage data every {$interval} seconds");
|
||||
|
||||
$loopStart = microtime(true);
|
||||
|
||||
/**
|
||||
* Aggregate InfluxDB every 30 seconds
|
||||
* @var InfluxDB\Client $client
|
||||
*/
|
||||
$client = $register->get('influxdb');
|
||||
if ($client) {
|
||||
$attempts = 0;
|
||||
$max = 10;
|
||||
$sleep = 1;
|
||||
|
||||
$database = $client->selectDB('telegraf');
|
||||
do { // check if telegraf database is ready
|
||||
$attempts++;
|
||||
if(!in_array('telegraf', $client->listDatabases())) {
|
||||
Console::warning("InfluxDB not ready. Retrying connection ({$attempts})...");
|
||||
if($attempts >= $max) {
|
||||
throw new \Exception('InfluxDB database not ready yet');
|
||||
}
|
||||
sleep($sleep);
|
||||
} else {
|
||||
break; // leave the do-while if successful
|
||||
}
|
||||
} while ($attempts < $max);
|
||||
|
||||
// sync data
|
||||
foreach ($globalMetrics as $metric => $options) { //for each metrics
|
||||
foreach ($periods as $period) { // aggregate data for each period
|
||||
$start = DateTime::createFromFormat('U', \strtotime($period['startTime']))->format(DateTime::RFC3339);
|
||||
if (!empty($latestTime[$metric][$period['key']])) {
|
||||
$start = DateTime::createFromFormat('U', $latestTime[$metric][$period['key']])->format(DateTime::RFC3339);
|
||||
}
|
||||
$end = DateTime::createFromFormat('U', \strtotime('now'))->format(DateTime::RFC3339);
|
||||
|
||||
$table = $options['table']; //Which influxdb table to query for this metric
|
||||
$groupBy = empty($options['groupBy']) ? '' : ', "' . $options['groupBy'] . '"'; //Some sub level metrics may be grouped by other tags like collectionId, bucketId, etc
|
||||
|
||||
$filters = $options['filters'] ?? []; // Some metrics might have additional filters, like function's status
|
||||
if (!empty($filters)) {
|
||||
$filters = ' AND ' . implode(' AND ', array_map(function ($filter, $value) {
|
||||
return '"' . $filter . '"=\'' . $value . '\'';
|
||||
}, array_keys($filters), array_values($filters)));
|
||||
}
|
||||
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "' . $table . '" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\'' . (empty($filters) ? '' : $filters) . ' GROUP BY time(' . $period['key'] . '), "projectId"' . $groupBy . ' FILL(null)');
|
||||
|
||||
$points = $result->getPoints();
|
||||
foreach ($points as $point) {
|
||||
$projectId = $point['projectId'];
|
||||
|
||||
if (!empty($projectId) && $projectId != 'console') {
|
||||
$dbForProject->setNamespace('project_' . $projectId . '_internal');
|
||||
$metricUpdated = $metric;
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$groupedBy = $point[$options['groupBy']] ?? '';
|
||||
if (empty($groupedBy)) {
|
||||
continue;
|
||||
}
|
||||
$metricUpdated = str_replace($options['groupBy'], $groupedBy, $metric);
|
||||
}
|
||||
|
||||
$time = \strtotime($point['time']);
|
||||
$id = \md5($time . '_' . $period['key'] . '_' . $metricUpdated); //Construct unique id for each metric using time, period and metric
|
||||
$value = (!empty($point['value'])) ? $point['value'] : 0;
|
||||
|
||||
try {
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'period' => $period['key'],
|
||||
'time' => $time,
|
||||
'metric' => $metricUpdated,
|
||||
'value' => $value,
|
||||
'type' => 0,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $value));
|
||||
}
|
||||
$latestTime[$metric][$period['key']] = $time;
|
||||
} catch (\Exception $e) { // if projects are deleted this might fail
|
||||
Console::warning("Failed to save data for project {$projectId} and metric {$metricUpdated}: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregate MariaDB every 15 minutes
|
||||
* Some of the queries here might contain full-table scans.
|
||||
*/
|
||||
if ($iterations % 30 == 0) { // Every 15 minutes aggregate number of objects in database
|
||||
|
||||
$latestProject = null;
|
||||
|
||||
do { // Loop over all the projects
|
||||
$attempts = 0;
|
||||
$max = 10;
|
||||
$sleep = 1;
|
||||
|
||||
do { // list projects
|
||||
try {
|
||||
$attempts++;
|
||||
$projects = $dbForConsole->find('projects', [], 100, cursor:$latestProject);
|
||||
break; // leave the do-while if successful
|
||||
} catch (\Exception $e) {
|
||||
Console::warning("Console DB not ready yet. Retrying ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception('Failed access console db: ' . $e->getMessage());
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
} while ($attempts < $max);
|
||||
|
||||
if (empty($projects)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$latestProject = $projects[array_key_last($projects)];
|
||||
|
||||
foreach ($projects as $project) {
|
||||
$projectId = $project->getId();
|
||||
|
||||
// Get total storage
|
||||
$dbForProject->setNamespace('project_' . $projectId . '_internal');
|
||||
$storageTotal = $dbForProject->sum('files', 'sizeOriginal') + $dbForProject->sum('tags', 'size');
|
||||
|
||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||
$id = \md5($time . '_30m_storage.total'); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'period' => '30m',
|
||||
'time' => $time,
|
||||
'metric' => 'storage.total',
|
||||
'value' => $storageTotal,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $storageTotal));
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
$id = \md5($time . '_1d_storage.total'); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'period' => '1d',
|
||||
'time' => $time,
|
||||
'metric' => 'storage.total',
|
||||
'value' => $storageTotal,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $storageTotal));
|
||||
}
|
||||
|
||||
$collections = [
|
||||
'users' => [
|
||||
'namespace' => 'internal',
|
||||
],
|
||||
'collections' => [
|
||||
'metricPrefix' => 'database',
|
||||
'namespace' => 'internal',
|
||||
'subCollections' => [ // Some collections, like collections and later buckets have child collections that need counting
|
||||
'documents' => [
|
||||
'namespace' => 'external',
|
||||
],
|
||||
],
|
||||
],
|
||||
'files' => [
|
||||
'metricPrefix' => 'storage',
|
||||
'namespace' => 'internal',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($collections as $collection => $options) {
|
||||
try {
|
||||
$dbForProject->setNamespace("project_{$projectId}_{$options['namespace']}");
|
||||
$count = $dbForProject->count($collection);
|
||||
$dbForProject->setNamespace("project_{$projectId}_internal");
|
||||
$metricPrefix = $options['metricPrefix'] ?? '';
|
||||
$metric = empty($metricPrefix) ? "{$collection}.count" : "{$metricPrefix}.{$collection}.count";
|
||||
|
||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'time' => $time,
|
||||
'period' => '30m',
|
||||
'metric' => $metric,
|
||||
'value' => $count,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
$id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'time' => $time,
|
||||
'period' => '1d',
|
||||
'metric' => $metric,
|
||||
'value' => $count,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
}
|
||||
|
||||
$subCollections = $options['subCollections'] ?? [];
|
||||
|
||||
if (empty($subCollections)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$latestParent = null;
|
||||
$subCollectionCounts = []; //total project level count of sub collections
|
||||
|
||||
do { // Loop over all the parent collection document for each sub collection
|
||||
$dbForProject->setNamespace("project_{$projectId}_{$options['namespace']}");
|
||||
$parents = $dbForProject->find($collection, [], 100, cursor:$latestParent); // Get all the parents for the sub collections for example for documents, this will get all the collections
|
||||
|
||||
if (empty($parents)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$latestParent = $parents[array_key_last($parents)];
|
||||
|
||||
foreach ($parents as $parent) {
|
||||
foreach ($subCollections as $subCollection => $subOptions) { // Sub collection counts, like database.collections.collectionId.documents.count
|
||||
$dbForProject->setNamespace("project_{$projectId}_{$subOptions['namespace']}");
|
||||
$count = $dbForProject->count($parent->getId());
|
||||
|
||||
$subCollectionCounts[$subCollection] = ($subCollectionCounts[$subCollection] ?? 0) + $count; // Project level counts for sub collections like database.documents.count
|
||||
|
||||
$dbForProject->setNamespace("project_{$projectId}_internal");
|
||||
|
||||
$metric = empty($metricPrefix) ? "{$collection}.{$parent->getId()}.{$subCollection}.count" : "{$metricPrefix}.{$collection}.{$parent->getId()}.{$subCollection}.count";
|
||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'time' => $time,
|
||||
'period' => '30m',
|
||||
'metric' => $metric,
|
||||
'value' => $count,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
$id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'time' => $time,
|
||||
'period' => '1d',
|
||||
'metric' => $metric,
|
||||
'value' => $count,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!empty($parents));
|
||||
|
||||
/**
|
||||
* Inserting project level counts for sub collections like database.documents.count
|
||||
*/
|
||||
foreach ($subCollectionCounts as $subCollection => $count) {
|
||||
$dbForProject->setNamespace("project_{$projectId}_internal");
|
||||
|
||||
$metric = empty($metricPrefix) ? "{$subCollection}.count" : "{$metricPrefix}.{$subCollection}.count";
|
||||
|
||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'time' => $time,
|
||||
'period' => '30m',
|
||||
'metric' => $metric,
|
||||
'value' => $count,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
}
|
||||
|
||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||
$id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||
$document = $dbForProject->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'time' => $time,
|
||||
'period' => '1d',
|
||||
'metric' => $metric,
|
||||
'value' => $count,
|
||||
'type' => 1,
|
||||
]));
|
||||
} else {
|
||||
$dbForProject->updateDocument('stats', $document->getId(),
|
||||
$document->setAttribute('value', $count));
|
||||
}
|
||||
}
|
||||
} catch (\Exception$e) {
|
||||
Console::warning("Failed to save database counters data for project {$collection}: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!empty($projects));
|
||||
}
|
||||
|
||||
$iterations++;
|
||||
$loopTook = microtime(true) - $loopStart;
|
||||
$now = date('d-m-Y H:i:s', time());
|
||||
|
||||
Console::info("[{$now}] Aggregation took {$loopTook} seconds");
|
||||
}, $interval);
|
||||
});
|
|
@ -251,7 +251,7 @@
|
|||
</span>
|
||||
|
||||
<div class="pull-start margin-end avatar-container">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{session.clientCode|lowercase}}?width=60&height=60&project={{env.PROJECT}},title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{session.clientCode|lowercase}}?width=60&height=60&project={{env.PROJECT}},title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" />
|
||||
|
||||
<div data-ls-if="{{session.provider}} !== 'email'" class="corner">
|
||||
<img data-ls-attrs="src=/images/users/{{session.provider}}.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{session.provider}},alt={{session.provider}}" class="avatar xs" loading="lazy" width="30" height="30" />
|
||||
|
@ -266,7 +266,7 @@
|
|||
</span>
|
||||
|
||||
<div class="margin-top-small">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-if="{{session.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{session.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs margin-end-small inline" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{session.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{session.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs margin-end-small inline" />
|
||||
<small data-ls-bind="{{session.ip}}"></small> / <small data-ls-bind="{{session.countryName}}"></small>
|
||||
</div>
|
||||
</li>
|
||||
|
@ -308,7 +308,7 @@
|
|||
<th width="120">Date</th>
|
||||
<th width="175">Event</th>
|
||||
<th>Client</th>
|
||||
<th width="90">Location</th>
|
||||
<th width="110">Location</th>
|
||||
<th width="90">IP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -317,13 +317,13 @@
|
|||
<td data-title="Date: "><span data-ls-bind="{{log.time|dateTime}}"></span></td>
|
||||
<td data-title="Event: "><span data-ls-bind="{{log.event}}"></span></td>
|
||||
<td data-title="Client: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-if="(!{{log.clientName}})">Unknown</span>
|
||||
<span data-ls-if="({{log.clientName}})" data-ls-bind="{{log.clientName}} {{log.clientVersion}} on {{log.model}} {{log.osName}} {{log.osVersion}}"></span>
|
||||
</td>
|
||||
<td data-title="Location: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.geo.countryName}}"></span>
|
||||
<img onerror="this.onerror=null;this.className='avatar xxs hide'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.countryName}}"></span>
|
||||
</td>
|
||||
<td data-title="IP: "><span data-ls-bind="{{log.ip}}"></span></td>
|
||||
</tr>
|
||||
|
|
|
@ -21,7 +21,7 @@ $interval = floor((int)$this->getParam('interval', 0) / 86400);
|
|||
<th width="120">Date</th>
|
||||
<th width="180">Initiator</th>
|
||||
<th>Event</th>
|
||||
<th width="90">Location</th>
|
||||
<th width="110">Location</th>
|
||||
<th width="90">IP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -32,13 +32,15 @@ $interval = floor((int)$this->getParam('interval', 0) / 86400);
|
|||
<span data-ls-if="{{log.userName|escape}} !== '' && {{log.mode}} === ''"><i class="icon-user"></i> <a data-ls-attrs="href=/console/users/user?id={{log.userId}}&project={{router.params.project}}" data-ls-bind="{{log.userName}}"></a></span>
|
||||
<span data-ls-if="{{log.userName|escape}} === '' && {{log.userEmail}} !== '' && {{log.mode}} !== 'key'"><i class="icon-user"></i> Unknown</span>
|
||||
<span data-ls-if="{{log.userName|escape}} === '' && {{log.userEmail}} === '' && {{log.mode}} !== 'key'"><i class="icon-user"></i> Anonymous User</span>
|
||||
<span data-ls-if="{{log.mode}} === 'admin'"><i class="icon-user"></i> <span data-ls-bind="{{log.userName}} (Admin)"></span></span>
|
||||
<span data-ls-if="{{log.mode}} === 'admin'">
|
||||
<img src="" data-ls-attrs="src={{log.userName|avatar}}" data-size="45" alt="User Avatar" class="avatar xxs inline margin-end-small" loading="lazy" width="30" height="30" /> <span data-ls-bind="{{log.userName}}"></span> <span class="text-fade text-size-xs">(Admin)</span>
|
||||
</span>
|
||||
<span data-ls-if="{{log.mode}} === 'key'"> <i class="icon-key"></i> API Key</span>
|
||||
</td>
|
||||
<td data-title="Event: "><span data-ls-bind="{{log.event}}"></span></td>
|
||||
<td data-title="Location: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.geo.countryName}}"></span>
|
||||
<img onerror="this.onerror=null;this.className='avatar xxs hide'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.countryName}}"></span>
|
||||
</td>
|
||||
<td data-title="IP: "><span data-ls-bind="{{log.ip}}"></span></td>
|
||||
</tr>
|
||||
|
|
|
@ -57,7 +57,7 @@ $logs = $this->getParam('logs', null);
|
|||
</div>
|
||||
|
||||
<div data-ls-if="({{project-documents.sum}})" class="margin-top-negative">
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small"><span data-ls-bind="{{project-documents.sum}}"></span> documents found</div>
|
||||
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-documents.sum}}"></span> documents found</div>
|
||||
|
||||
<div class="box margin-bottom y-scroll text-size-small">
|
||||
<table class="vertical borders">
|
||||
|
@ -65,14 +65,14 @@ $logs = $this->getParam('logs', null);
|
|||
<tr data-ls-loop="project-collection.attributes" data-ls-as="attribute" data-ls-prefix="template-attribute-title-first" data-ls-limit="20">
|
||||
<td style="width: 170px">
|
||||
<i data-ls-attrs="class=pull-end icon-{{attribute.type}} text-size-xs"></i>
|
||||
<span class="text-bold" data-ls-bind="{{attribute.$id}}"></span>
|
||||
<span class="text-bold" data-ls-bind="{{attribute.key}}"></span>
|
||||
<span class="text-size-small" data-ls-if="{{attribute.array}}">[]</span>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-ls-loop="project-documents.documents" data-ls-as="node">
|
||||
<tr data-ls-loop="project-collection.attributes" data-ls-as="attribute" data-ls-prefix="template-attribute-body-first" data-ls-limit="20">
|
||||
<td data-ls-attrs="data-title={{attribute.$id}}: ">
|
||||
<td data-ls-attrs="data-title={{attribute.key}}: ">
|
||||
<!-- <a href="" target="_blank" rel="noopener" class="pull-end margin-start"><i class="icon-link-ext"></i></a> -->
|
||||
<a data-ls-attrs="href=/console/database/document?id={{node.$id}}&collection={{router.params.id}}&project={{router.params.project}}"><span data-ls-bind="{{node|documentAttribute}}"></span></a>
|
||||
<span data-ls-if="!{{node|documentAttribute}}" class="text-fade">n/a</span>
|
||||
|
@ -130,17 +130,17 @@ $logs = $this->getParam('logs', null);
|
|||
<h2>Attributes</h2>
|
||||
|
||||
<div class="clear box margin-bottom">
|
||||
<div data-ls-if="0 == {{project-collection.attributes.length}} && 0 == {{project-collection.attributesInQueue.length}}">
|
||||
<div data-ls-if="0 == {{project-collection.attributes.length}}">
|
||||
<h3 class="margin-bottom-small text-bold">No Attributes Found</h3>
|
||||
|
||||
<p class="margin-bottom-no">Add your first attribute to get started</p>
|
||||
</div>
|
||||
|
||||
<table class="vertical" data-ls-if="0 < {{project-collection.attributes.length}} || 0 < {{project-collection.attributesInQueue.length}}">
|
||||
<table class="vertical" data-ls-if="0 < {{project-collection.attributes.length}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="30"></th>
|
||||
<th width="80"></th>
|
||||
<th width="100"></th>
|
||||
<th width="130">Attribute ID</th>
|
||||
<th width="100">Type</th>
|
||||
<th width="180">Default</th>
|
||||
|
@ -154,11 +154,14 @@ $logs = $this->getParam('logs', null);
|
|||
<i data-ls-attrs="class=icon-{{attribute.type}}"></i>
|
||||
</td>
|
||||
<td data-title="Status">
|
||||
<span class="text-size-small text-success">available </span>
|
||||
<span data-ls-if="{{attribute.status}} == 'available'" class="text-size-small text-success">available </span>
|
||||
<span data-ls-if="{{attribute.status}} == 'processing'" class="text-size-small text-info">processing </span>
|
||||
<span data-ls-if="{{attribute.status}} == 'failed'" class="text-size-small text-danger">failed </span>
|
||||
<span data-ls-if="{{attribute.status}} == 'deleting'" class="text-size-small text-danger">deleting </span>
|
||||
</td>
|
||||
|
||||
<td data-title="Attribute ID: ">
|
||||
<span class="text-size-small" data-ls-bind="{{attribute.$id}}"></span><span class="text-size-small" data-ls-if="{{attribute.size}}" data-ls-bind=" ({{attribute.size}})"></span>
|
||||
<span class="text-size-small" data-ls-bind="{{attribute.key}}"></span><span class="text-size-small" data-ls-if="{{attribute.size}}" data-ls-bind=" ({{attribute.size}})"></span>
|
||||
</td>
|
||||
|
||||
<td data-title="Type:">
|
||||
|
@ -176,7 +179,8 @@ $logs = $this->getParam('logs', null);
|
|||
</td>
|
||||
|
||||
<td data-title="">
|
||||
<form class="pull-end"
|
||||
<form data-ls-if="{{attribute.status}} !== 'deleting'"
|
||||
class="pull-end"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
|
@ -195,7 +199,7 @@ $logs = $this->getParam('logs', null);
|
|||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
<input type="hidden" name="collectionId" data-ls-bind="{{project-collection.$id}}" />
|
||||
<input type="hidden" name="attributeId" data-ls-bind="{{attribute.$id}}" />
|
||||
<input type="hidden" name="attributeId" data-ls-bind="{{attribute.key}}" />
|
||||
|
||||
<button class="danger small">Delete</button>
|
||||
</form>
|
||||
|
@ -203,54 +207,30 @@ $logs = $this->getParam('logs', null);
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr data-ls-if="0 < {{project-collection.attributesInQueue.length}}" />
|
||||
|
||||
<table class="vertical" data-ls-if="0 < {{project-collection.attributesInQueue.length}}">
|
||||
<tbody data-ls-loop="project-collection.attributesInQueue" data-ls-as="attribute">
|
||||
<tr>
|
||||
<td width="30">
|
||||
<i data-ls-attrs="class=icon-{{attribute.type}}"></i>
|
||||
</td>
|
||||
<td width="80" data-title="Status">
|
||||
<span class="text-size-small text-info">creating </span>
|
||||
</td>
|
||||
|
||||
<td width="130" data-title="Attribute ID: ">
|
||||
<span class="text-size-small" data-ls-bind="{{attribute.$id}}"></span><span class="text-size-small" data-ls-if="{{attribute.size}}" data-ls-bind=" ({{attribute.size}})"></span>
|
||||
</td>
|
||||
|
||||
<td width="100" data-title="Type:">
|
||||
<span class="text-size-small" data-ls-bind="{{attribute.type}}"></span>
|
||||
<span class="text-size-small" data-ls-if="{{attribute.array}}">[]</span>
|
||||
</td>
|
||||
|
||||
<td width="180" data-title="Default:">
|
||||
<span class="text-size-small" data-ls-bind="{{attribute.default}}" data-ls-attr="title={{attribute.default}}"></span>
|
||||
<span class="text-fade text-size-small" data-ls-if="!({{attribute.default}})">n/a</span>
|
||||
</td>
|
||||
|
||||
<td data-title="">
|
||||
<span class="text-size-small text-danger" data-ls-if="{{attribute.required}}">required</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="drop-list pull-start" data-ls-ui-open="" data-button-aria="Choose Platform" data-button-text="Add Attribute" data-button-class="button" data-blur="1">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="link new-attribute-string"><img src="/images/clients/web.png?v=<?php echo APP_CACHE_BUSTER; ?>" alt="String Attribute Logo" class="avatar xxs margin-end-small" loading="lazy" /> New String Attribute</div>
|
||||
<div class="link new-attribute-string"><i class="avatar icon-string"></i> New String Attribute</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="link new-attribute-integer"><img src="/images/clients/web.png?v=<?php echo APP_CACHE_BUSTER; ?>" alt="String Attribute Logo" class="avatar xxs margin-end-small" loading="lazy" /> New Integer Attribute</div>
|
||||
<div class="link new-attribute-integer"><i class="avatar icon-integer"></i> New Integer Attribute</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="link new-attribute-float"><img src="/images/clients/web.png?v=<?php echo APP_CACHE_BUSTER; ?>" alt="String Attribute Logo" class="avatar xxs margin-end-small" loading="lazy" /> New Float Attribute</div>
|
||||
<div class="link new-attribute-float"><i class="avatar icon-float"></i> New Float Attribute</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="link new-attribute-boolean"><img src="/images/clients/web.png?v=<?php echo APP_CACHE_BUSTER; ?>" alt="String Attribute Logo" class="avatar xxs margin-end-small" loading="lazy" /> New Boolean Attribute</div>
|
||||
<div class="link new-attribute-boolean"><i class="avatar icon-boolean"></i> New Boolean Attribute</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="link new-attribute-url"><i class="avatar icon-link"></i> New URL Attribute</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="link new-attribute-email"><i class="avatar icon-mail"></i> New Email Attribute</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="link new-attribute-ip"><i class="avatar icon-ip"></i> New IP Attribute</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -259,13 +239,13 @@ $logs = $this->getParam('logs', null);
|
|||
<h2>Indexes</h2>
|
||||
|
||||
<div class="clear box margin-bottom">
|
||||
<div data-ls-if="0 == {{project-collection.indexes.length}} && 0 == {{project-collection.indexesInQueue.length}}">
|
||||
<div data-ls-if="0 == {{project-collection.indexes.length}}">
|
||||
<h3 class="margin-bottom-small text-bold">No Indexes Found</h3>
|
||||
|
||||
<p class="margin-bottom-no">Add your first index to get started</p>
|
||||
</div>
|
||||
|
||||
<table class="vertical multi-line" data-ls-if="0 < {{project-collection.indexes.length}} || 0 < {{project-collection.indexesInQueue.length}}">
|
||||
<table class="vertical multi-line" data-ls-if="0 < {{project-collection.indexes.length}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="30"></th>
|
||||
|
@ -284,11 +264,14 @@ $logs = $this->getParam('logs', null);
|
|||
</td>
|
||||
|
||||
<td data-title="Status">
|
||||
<span class="text-size-small text-success">available</span>
|
||||
<span data-ls-if="{{index.status}} == 'available'" class="text-size-small text-success">available </span>
|
||||
<span data-ls-if="{{index.status}} == 'processing'" class="text-size-small text-info">processing </span>
|
||||
<span data-ls-if="{{index.status}} == 'failed'" class="text-size-small text-danger">failed </span>
|
||||
<span data-ls-if="{{index.status}} == 'deleting'" class="text-size-small text-danger">deleting </span>
|
||||
</td>
|
||||
|
||||
<td data-title="Index ID: ">
|
||||
<span class="text-size-small" data-ls-bind="{{index.$id}}"></span><span class="text-size-small" data-ls-if="{{index.size}}" data-ls-bind="({{index.size}})"></span>
|
||||
<span class="text-size-small" data-ls-bind="{{index.key}}"></span><span class="text-size-small" data-ls-if="{{index.size}}" data-ls-bind="({{index.size}})"></span>
|
||||
</td>
|
||||
|
||||
<td data-title="Type:">
|
||||
|
@ -305,7 +288,8 @@ $logs = $this->getParam('logs', null);
|
|||
</td>
|
||||
|
||||
<td data-title="">
|
||||
<form class="pull-end"
|
||||
<form data-ls-if="{{index.status}} !== 'deleting'"
|
||||
class="pull-end"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
|
@ -324,7 +308,7 @@ $logs = $this->getParam('logs', null);
|
|||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
<input type="hidden" name="collectionId" data-ls-bind="{{project-collection.$id}}" />
|
||||
<input type="hidden" name="indexId" data-ls-bind="{{index.$id}}" />
|
||||
<input type="hidden" name="indexId" data-ls-bind="{{index.key}}" />
|
||||
|
||||
<button class="danger small">Delete</button>
|
||||
</form>
|
||||
|
@ -332,43 +316,6 @@ $logs = $this->getParam('logs', null);
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr data-ls-if="0 < {{project-collection.indexesInQueue.length}}" />
|
||||
|
||||
<table class="vertical multi-line" data-ls-if="0 < {{project-collection.indexesInQueue.length}}">
|
||||
<tbody data-ls-loop="project-collection.indexesInQueue" data-ls-as="index">
|
||||
<tr>
|
||||
<td width="30">
|
||||
<i class="icon-key"></i>
|
||||
</td>
|
||||
|
||||
<td width="80" data-title="Status">
|
||||
<span class="text-size-small text-info">creating</span>
|
||||
</td>
|
||||
|
||||
<td width="130" data-title="Index ID: ">
|
||||
<span class="text-size-small" data-ls-bind="{{index.$id}}"></span><span class="text-size-small" data-ls-if="{{index.size}}" data-ls-bind="({{index.size}})"></span>
|
||||
</td>
|
||||
|
||||
<td width="100" data-title="Type:">
|
||||
<span class="text-size-small" data-ls-bind="{{index.type}}"></span>
|
||||
<span class="text-size-small" data-ls-if="{{index.array}}">[]</span>
|
||||
</td>
|
||||
|
||||
<td width="180" data-title="Attributes:">
|
||||
<span class="text-size-small" data-ls-bind="{{index|indexAttributes}}"></span>
|
||||
</td>
|
||||
|
||||
<td data-title="">
|
||||
<span class="text-size-small text-danger" data-ls-if="{{index.required}}">required</span>
|
||||
</td>
|
||||
|
||||
<td width="80" data-title="">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button class="new-index">Add Index</button>
|
||||
|
@ -417,7 +364,7 @@ $logs = $this->getParam('logs', null);
|
|||
<hr class="margin-top-small" />
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-1"><input type="radio" class="margin-top-no" /></div>
|
||||
<div class="col span-1"><input name="permission" value="document" type="radio" class="margin-top-no" data-ls-bind="{{project-collection.permission}}" /></div>
|
||||
<div class="col span-11">
|
||||
<b>Document Level</b>
|
||||
<p class="text-fade margin-top-tiny">Bla bla bla bla bla Bla blabla bla Bla blabla bla Bla blabla bla Bla blaBla bla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla</p>
|
||||
|
@ -425,7 +372,7 @@ $logs = $this->getParam('logs', null);
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-1"><input type="radio" class="margin-top-tiny" /></div>
|
||||
<div class="col span-1"><input name="permission" value="collection" type="radio" class="margin-top-tiny" data-ls-bind="{{project-collection.permission}}" /></div>
|
||||
<div class="col span-11">
|
||||
<b>Collection Level</b>
|
||||
<p class="text-fade margin-top-tiny">Bla bla bla Bla blabla bla Bla blabla bla Bla blabla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla Bla bla bla Bla</p>
|
||||
|
@ -526,7 +473,7 @@ $logs = $this->getParam('logs', null);
|
|||
<input id="string-default" name="default" type="text" class="margin-bottom-large" autocomplete="off">
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -569,19 +516,107 @@ $logs = $this->getParam('logs', null);
|
|||
<div class="row responsive thin">
|
||||
<div class="col span-6 margin-bottom-small">
|
||||
<label for="integer-min">Min</label>
|
||||
<input type="text" class="full-width" name="number" value="0" required autocomplete="off" />
|
||||
<input id="integer-min" type="number" class="full-width" name="min" value="0" required autocomplete="off" data-cast-to="integer" />
|
||||
</div>
|
||||
<div class="col span-6 margin-bottom-small">
|
||||
<label for="integer-min">Max</label>
|
||||
<input type="text" class="full-width" name="number" value="0" required autocomplete="off" />
|
||||
<label for="integer-max">Max</label>
|
||||
<input id="integer-max" type="number" class="full-width" name="max" value="0" required autocomplete="off" data-cast-to="integer" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="integer-default">Default Value</label>
|
||||
<input id="integer-default" name="default" type="number" value="0" class="margin-bottom-large" autocomplete="off">
|
||||
<input id="integer-default" name="default" type="number" value="0" class="margin-bottom-large" autocomplete="off" data-cast-to="integer">
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal box close sticky-footer" data-button-alias=".new-attribute-email">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h1>Add Email Attribute</h1>
|
||||
|
||||
<form
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Create Collection Attribute (email)"
|
||||
data-service="database.createEmailAttribute"
|
||||
data-scope="sdk"
|
||||
data-event="submit"
|
||||
data-success="alert,trigger,reset"
|
||||
data-success-param-alert-text="Created new attribute successfully"
|
||||
data-success-param-trigger-events="database.createAttribute"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
||||
|
||||
<label for="string-attributeId">Attribute ID</label>
|
||||
<input type="text" class="full-width" name="attributeId" required autocomplete="off" maxlength="128" />
|
||||
|
||||
<div class="margin-bottom">
|
||||
<input name="required" type="hidden" data-forms-switch data-cast-to="boolean" /> Required <span class="tooltip" data-tooltip="Mark whether this is a required attribute"><i class="icon-info-circled"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="margin-bottom">
|
||||
<input name="array" type="hidden" data-forms-switch data-cast-to="boolean" /> Array <span class="tooltip" data-tooltip="Mark whether this attribute should act as an array"><i class="icon-info-circled"></i></span>
|
||||
</div>
|
||||
|
||||
<label for="string-default">Default Value</label>
|
||||
<input id="string-default" name="default" type="email" placeholder="demo@appwrite.io" class="margin-bottom-large" autocomplete="off">
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal box close sticky-footer" data-button-alias=".new-attribute-url">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h1>Add URL Attribute</h1>
|
||||
|
||||
<form
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Create Collection Attribute (url)"
|
||||
data-service="database.createUrlAttribute"
|
||||
data-scope="sdk"
|
||||
data-event="submit"
|
||||
data-success="alert,trigger,reset"
|
||||
data-success-param-alert-text="Created new attribute successfully"
|
||||
data-success-param-trigger-events="database.createAttribute"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
||||
|
||||
<label for="string-attributeId">Attribute ID</label>
|
||||
<input type="text" class="full-width" name="attributeId" required autocomplete="off" maxlength="128" />
|
||||
|
||||
<div class="margin-bottom">
|
||||
<input name="required" type="hidden" data-forms-switch data-cast-to="boolean" /> Required <span class="tooltip" data-tooltip="Mark whether this is a required attribute"><i class="icon-info-circled"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="margin-bottom">
|
||||
<input name="array" type="hidden" data-forms-switch data-cast-to="boolean" /> Array <span class="tooltip" data-tooltip="Mark whether this attribute should act as an array"><i class="icon-info-circled"></i></span>
|
||||
</div>
|
||||
|
||||
<label for="string-default">Default Value</label>
|
||||
<input id="string-default" name="default" type="url" placeholder="https://appwrite.io/my-link" class="margin-bottom-large" autocomplete="off">
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -598,7 +633,7 @@ $logs = $this->getParam('logs', null);
|
|||
<p>Please add your first attribute before adding your first index.</p>
|
||||
</div>
|
||||
|
||||
<button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</div>
|
||||
|
||||
<form data-ls-if="0 < {{project-collection.attributes.length}}"
|
||||
|
@ -639,7 +674,7 @@ $logs = $this->getParam('logs', null);
|
|||
<div class="row responsive thin margin-bottom-tiny">
|
||||
<div class="col span-7 margin-bottom-small">
|
||||
<select data-duplications data-ls-attrs="name=attributes" data-ls-loop="project-collection.attributes" data-ls-as="option" data-cast-to="array" class="margin-bottom-no">
|
||||
<option data-ls-attrs="value={{option.$id}}" data-ls-bind="{{option.$id}}"></option>
|
||||
<option data-ls-attrs="value={{option.key}}" data-ls-bind="{{option.key}}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col span-4 margin-bottom-small">
|
||||
|
@ -656,7 +691,7 @@ $logs = $this->getParam('logs', null);
|
|||
</div>
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -71,11 +71,11 @@
|
|||
<ul data-ls-loop="project-collection.attributes" data-ls-as="attribute">
|
||||
<li>
|
||||
<label>
|
||||
<div data-ls-bind="{{attribute.$id}}" class="margin-bottom-tiny"></div>
|
||||
<div data-ls-bind="{{attribute.key}}" class="margin-bottom-tiny"></div>
|
||||
<div data-ls-if="{{attribute.required}}" class="text-size-xs text-danger text-fade">required</div>
|
||||
<div data-ls-if="!{{attribute.required}}" class="text-size-xs text-fade">optional</div>
|
||||
</label>
|
||||
<textarea data-ls-attrs="name={{attribute.$id}}" data-ls-bind="{{project-document|documentAttribute}}"></textarea>
|
||||
<textarea data-ls-attrs="name={{attribute.key}}" data-ls-bind="{{project-document|documentAttribute}}"></textarea>
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
|
|
@ -107,9 +107,9 @@
|
|||
<label for="collection-name">Name</label>
|
||||
<input type="text" class="full-width" id="collection-name" name="name" required autocomplete="off" maxlength="128" />
|
||||
|
||||
<input type="hidden" id="collection-permission" name="permission" required value="document" />
|
||||
<input type="hidden" id="collection-read" name="read" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
|
||||
<input type="hidden" id="collection-write" name="write" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
|
||||
<input type="hidden" id="collection-rules" name="rules" required data-cast-to="json" value="{}" />
|
||||
|
||||
<hr />
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ $runtimes = $this->getParam('runtimes', []);
|
|||
</div>
|
||||
|
||||
<div data-ls-if="0 != {{project-functions.functions.length}}">
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small margin-top-negative"><span data-ls-bind="{{project-functions.sum}}"></span> functions found</div>
|
||||
<div class="margin-bottom-small text-align-end text-size-small margin-top-negative text-fade"><span data-ls-bind="{{project-functions.sum}}"></span> functions found</div>
|
||||
|
||||
<div class="box margin-bottom">
|
||||
<ul data-ls-loop="project-functions.functions" data-ls-as="function" class="list">
|
||||
|
|
|
@ -129,7 +129,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
</div>
|
||||
<div class="col span-3">
|
||||
<div class="value"><span class="sum" data-ls-bind="{{usage.functions.total|statsTotal}}" data-default="0">0</span></div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Func. Executions</b></div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Executions</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -290,7 +290,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@ -322,7 +322,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
@ -358,7 +358,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@ -398,7 +398,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
@ -432,7 +432,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -465,7 +465,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -498,7 +498,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -531,7 +531,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Register</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -565,7 +565,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
@ -596,7 +596,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
@ -628,7 +628,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
|
||||
<hr />
|
||||
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Back</button>
|
||||
<button type="submit">Update</button> <button data-ls-ui-trigger="modal-close" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
|||
</div>
|
||||
|
||||
<div data-ls-if="0 != {{project-files.sum}}">
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small"><span data-ls-bind="{{project-files.sum}}"></span> files found</div>
|
||||
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-files.sum}}"></span> files found</div>
|
||||
|
||||
<div class="box margin-bottom">
|
||||
<table class="vertical">
|
||||
|
|
|
@ -56,7 +56,7 @@ $auth = $this->getParam('auth', []);
|
|||
</div>
|
||||
|
||||
<div data-ls-if="0 != {{project-users.sum}}">
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small"><span data-ls-bind="{{project-users.sum}}"></span> users found</div>
|
||||
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-users.sum}}"></span> users found</div>
|
||||
|
||||
<div class="box margin-bottom">
|
||||
<table class="vertical">
|
||||
|
@ -223,7 +223,7 @@ $auth = $this->getParam('auth', []);
|
|||
</div>
|
||||
|
||||
<div data-ls-if="0 != {{project-teams.sum}}">
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small"><span data-ls-bind="{{project-teams.sum}}"></span> results found</div>
|
||||
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-teams.sum}}"></span> teams found</div>
|
||||
|
||||
<div class="box margin-bottom">
|
||||
<table class="vertical">
|
||||
|
@ -423,13 +423,13 @@ $auth = $this->getParam('auth', []);
|
|||
data-scope="console">
|
||||
<ul class="tiles cell-3 margin-bottom-small">
|
||||
<?php foreach ($providers as $provider => $data):
|
||||
if (isset($data['enabled']) && !$data['enabled']) {continue;}
|
||||
if (isset($data['mock']) && $data['mock']) {continue;}
|
||||
$sandbox = $data['sandbox'] ?? false;
|
||||
$form = $data['form'] ?? false;
|
||||
$name = $data['name'] ?? 'Unknown';
|
||||
$beta = $data['beta'] ?? false;
|
||||
?>
|
||||
if (isset($data['enabled']) && !$data['enabled']) {continue;}
|
||||
// if (isset($data['mock']) && $data['mock']) {continue;}
|
||||
$sandbox = $data['sandbox'] ?? false;
|
||||
$form = $data['form'] ?? false;
|
||||
$name = $data['name'] ?? 'Unknown';
|
||||
$beta = $data['beta'] ?? false;
|
||||
?>
|
||||
<li class="<?php echo (isset($data['enabled']) && !$data['enabled']) ? 'dev-feature' : ''; ?>">
|
||||
<div data-ui-modal class="modal close" data-button-alias="none" data-open-event="provider-update-<?php echo $provider; ?>">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
</div>
|
||||
|
||||
<div data-ls-if="0 != {{project-members.sum}}">
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small margin-top-negative"><span data-ls-bind="{{project-members.sum}}"></span> memberships found</div>
|
||||
<div class="margin-bottom-small margin-end-small text-align-end text-size-small margin-top-negative text-fade"><span data-ls-bind="{{project-members.sum}}"></span> memberships found</div>
|
||||
|
||||
<div class="box margin-bottom">
|
||||
<ul data-ls-loop="project-members.memberships" data-ls-as="member" class="list">
|
||||
|
|
|
@ -17,6 +17,108 @@
|
|||
</h1>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal width-medium box close" data-button-hide="on" data-open-event="open-update-name">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h2>Update name</h2>
|
||||
|
||||
<form name="users.updateName"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Update User Name"
|
||||
data-service="users.updateName"
|
||||
data-scope="sdk"
|
||||
data-event="submit"
|
||||
data-success="trigger,alert"
|
||||
data-success-param-alert-text="User name was updated successfully"
|
||||
data-success-param-trigger-events="users.update"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to update user name"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">
|
||||
|
||||
<label for="name">Name</label>
|
||||
<input name="name" id="name" type="text" autocomplete="off" data-ls-bind="{{user.name}}" required class="full-width" maxlength="128">
|
||||
|
||||
<hr />
|
||||
|
||||
<footer>
|
||||
<button type="submit" class="">Update</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal width-medium box close" data-button-hide="on" data-open-event="open-update-email">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h2>Update Email</h2>
|
||||
|
||||
<form name="users.updateEmail"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Update User Email"
|
||||
data-service="users.updateEmail"
|
||||
data-scope="sdk"
|
||||
data-event="submit"
|
||||
data-success="trigger,alert"
|
||||
data-success-param-alert-text="User email was updated successfully"
|
||||
data-success-param-trigger-events="users.update"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to update user email"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">
|
||||
|
||||
<label for="email">Email</label>
|
||||
<input name="email" id="email" type="text" autocomplete="off" data-ls-bind="{{user.email}}" required class="full-width" maxlength="128">
|
||||
|
||||
<hr />
|
||||
|
||||
<footer>
|
||||
<button type="submit" class="">Update</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal width-medium box close" data-button-hide="on" data-open-event="open-update-password">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h2>Update Password</h2>
|
||||
|
||||
<form name="users.updatePassword"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Update User Password"
|
||||
data-service="users.updatePassword"
|
||||
data-scope="sdk"
|
||||
data-event="submit"
|
||||
data-success="trigger,alert"
|
||||
data-success-param-alert-text="User password was updated successfully"
|
||||
data-success-param-trigger-events="users.update"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to update user password"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input name="password" id="password" type="password" autocomplete="off" required class="full-width" maxlength="128">
|
||||
|
||||
<hr />
|
||||
|
||||
<footer>
|
||||
<button type="submit" class="">Update</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal width-large box close" data-button-hide="on" data-open-event="open-json">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
|
@ -134,6 +236,9 @@
|
|||
</div>
|
||||
|
||||
<ul class="margin-bottom-large text-fade text-size-small">
|
||||
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-update-name" class="link text-size-small">Update name</button></li>
|
||||
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-update-email" class="link text-size-small">Update Email</button></li>
|
||||
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-update-password" class="link text-size-small">Update Password</button></li>
|
||||
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-json" class="link text-size-small">View as JSON</button></li>
|
||||
</ul>
|
||||
|
||||
|
@ -218,7 +323,7 @@
|
|||
<button class="danger">Logout</button>
|
||||
</form>
|
||||
<div class="pull-start margin-end avatar-container">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{session.clientCode|lowercase}}?width=120&height=120&project={{env.PROJECT}},title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{session.clientCode|lowercase}}?width=120&height=120&project={{env.PROJECT}},title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" />
|
||||
|
||||
<div data-ls-if="{{session.provider}} !== 'email'" class="corner">
|
||||
<img data-ls-attrs="src=/images/users/{{session.provider}}.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{session.provider}},alt={{session.provider}}" class="avatar xs" loading="lazy" width="30" height="30" />
|
||||
|
@ -228,7 +333,7 @@
|
|||
<span data-ls-bind="{{session.clientName}}"></span> <span data-ls-bind="{{session.clientVersion}}"></span> on <span data-ls-bind="{{session.deviceModel}}"></span> <span data-ls-bind="{{session.osName}}"></span> <span data-ls-bind="{{session.osVersion}}"></span>
|
||||
|
||||
<div class="margin-top-small">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-if="{{session.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{session.countryCode}}?width=120&height=120&project={{env.PROJECT}}" class="avatar xxs margin-end-small inline" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{session.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{session.countryCode}}?width=120&height=120&project={{env.PROJECT}}" class="avatar xxs margin-end-small inline" />
|
||||
<small data-ls-bind="{{session.ip}}"></small> / <small data-ls-bind="{{session.countryName}}"></small>
|
||||
</div>
|
||||
</li>
|
||||
|
@ -285,12 +390,12 @@
|
|||
<td data-title="Date: "><span data-ls-bind="{{log.time|dateTime}}"></span></td>
|
||||
<td data-title="Event: "><span data-ls-bind="{{log.event}}"></span></td>
|
||||
<td data-title="Client: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-if="({{log.clientCode}})" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="({{log.clientCode}})" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-if="({{log.clientName}})" data-ls-bind="{{log.clientName}} {{log.clientVersion}} on {{log.model}} {{log.osName}} {{log.osVersion}}"></span>
|
||||
<div data-ls-if="(!{{log.clientName}})" class="text-align-center text-fade">Unknown</div>
|
||||
</td>
|
||||
<td data-title="Location: ">
|
||||
<img onerror="this.onerror=null;this.src='/images/unknown.svg'" data-ls-if="{{log.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||
<span data-ls-bind="{{log.countryName}}"></span>
|
||||
</td>
|
||||
<td data-title="IP: "><span data-ls-bind="{{log.ip}}"></span></td>
|
||||
|
|
|
@ -9,7 +9,7 @@ $image = $this->getParam('image', '');
|
|||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.3
|
||||
image: traefik:2.5
|
||||
container_name: appwrite-traefik
|
||||
command:
|
||||
- --providers.file.directory=/storage/config
|
||||
|
@ -294,6 +294,26 @@ services:
|
|||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
|
||||
appwrite-usage:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
entrypoint: usage
|
||||
container_name: appwrite-usage
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- influxdb
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_INFLUXDB_HOST
|
||||
- _APP_INFLUXDB_PORT
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-schedule:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
|
@ -324,7 +344,7 @@ services:
|
|||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
command: 'mysqld --innodb-flush-method=fsync --wait_timeout=86400'
|
||||
command: 'mysqld --innodb-flush-method=fsync'
|
||||
|
||||
redis:
|
||||
image: redis:6.0-alpine3.12
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Extend\PDO;
|
||||
use Utopia\App;
|
||||
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
|
||||
require_once __DIR__.'/init.php';
|
||||
|
||||
$register->set('db', function () {
|
||||
$dbHost = App::getEnv('_APP_DB_HOST', '');
|
||||
$dbUser = App::getEnv('_APP_DB_USER', '');
|
||||
$dbPass = App::getEnv('_APP_DB_PASS', '');
|
||||
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
|
||||
|
||||
$pdo = new PDO("mysql:host={$dbHost};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array(
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
));
|
||||
|
||||
return $pdo;
|
||||
});
|
||||
|
||||
$register->set('cache', function () { // Register cache connection
|
||||
$redis = new Redis();
|
||||
$redis->pconnect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
|
||||
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
|
||||
|
||||
return $redis;
|
||||
});
|
||||
|
|
@ -4,7 +4,7 @@ use Appwrite\Resque\Worker;
|
|||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Audits V1 Worker');
|
||||
Console::success(APP_NAME.' audits worker v1 has started');
|
||||
|
|
|
@ -9,7 +9,7 @@ use Utopia\Database\Query;
|
|||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Domains\Domain;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Certificates V1 Worker');
|
||||
Console::success(APP_NAME.' certificates worker v1 has started');
|
||||
|
|
|
@ -5,7 +5,7 @@ use Utopia\CLI\Console;
|
|||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Database V1 Worker');
|
||||
Console::success(APP_NAME.' database worker v1 has started'."\n");
|
||||
|
@ -20,31 +20,34 @@ class DatabaseV1 extends Worker
|
|||
|
||||
public function run(): void
|
||||
{
|
||||
Authorization::disable();
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
$type = $this->args['type'] ?? '';
|
||||
$collection = $this->args['collection'] ?? [];
|
||||
$collection = new Document($collection);
|
||||
$document = $this->args['document'] ?? [];
|
||||
$document = new Document($document);
|
||||
|
||||
Authorization::disable();
|
||||
if($collection->isEmpty()) {
|
||||
throw new Exception('Missing collection');
|
||||
}
|
||||
|
||||
if($document->isEmpty()) {
|
||||
throw new Exception('Missing document');
|
||||
}
|
||||
|
||||
switch (strval($type)) {
|
||||
case DATABASE_TYPE_CREATE_ATTRIBUTE:
|
||||
$attribute = $this->args['document'] ?? '';
|
||||
$attribute = new Document($attribute);
|
||||
$this->createAttribute($attribute, $projectId);
|
||||
$this->createAttribute($collection, $document, $projectId);
|
||||
break;
|
||||
case DATABASE_TYPE_DELETE_ATTRIBUTE:
|
||||
$attribute = $this->args['document'] ?? '';
|
||||
$attribute = new Document($attribute);
|
||||
$this->deleteAttribute($attribute, $projectId);
|
||||
$this->deleteAttribute($collection, $document, $projectId);
|
||||
break;
|
||||
case DATABASE_TYPE_CREATE_INDEX:
|
||||
$index = $this->args['document'] ?? '';
|
||||
$index = new Document($index);
|
||||
$this->createIndex($index, $projectId);
|
||||
$this->createIndex($collection, $document, $projectId);
|
||||
break;
|
||||
case DATABASE_TYPE_DELETE_INDEX:
|
||||
$index = $this->args['document'] ?? '';
|
||||
$index = new Document($index);
|
||||
$this->deleteIndex($index, $projectId);
|
||||
$this->deleteIndex($collection, $document, $projectId);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -60,76 +63,120 @@ class DatabaseV1 extends Worker
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function createAttribute($attribute, $projectId): void
|
||||
protected function createAttribute(Document $collection, Document $attribute, string $projectId): void
|
||||
{
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $attribute->getCollection();
|
||||
$id = $attribute->getAttribute('$id', '');
|
||||
$collectionId = $collection->getId();
|
||||
$key = $attribute->getAttribute('key', '');
|
||||
$type = $attribute->getAttribute('type', '');
|
||||
$size = $attribute->getAttribute('size', 0);
|
||||
$required = $attribute->getAttribute('required', false);
|
||||
$default = $attribute->getAttribute('default', null);
|
||||
$signed = $attribute->getAttribute('signed', true);
|
||||
$array = $attribute->getAttribute('array', false);
|
||||
$format = $attribute->getAttribute('format', null);
|
||||
$format = $attribute->getAttribute('format', '');
|
||||
$formatOptions = $attribute->getAttribute('formatOptions', []);
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
|
||||
$success = $dbForExternal->createAttribute($collectionId, $id, $type, $size, $required, $default, $signed, $array, $format, $filters);
|
||||
if ($success) {
|
||||
$removed = $dbForExternal->removeAttributeInQueue($collectionId, $id);
|
||||
try {
|
||||
if(!$dbForExternal->createAttribute($collectionId, $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||
throw new Exception('Failed to create Attribute');
|
||||
}
|
||||
$dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
|
||||
} catch (\Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
$dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed'));
|
||||
}
|
||||
|
||||
$dbForInternal->deleteCachedDocument('collections', $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteAttribute($attribute, $projectId): void
|
||||
protected function deleteAttribute(Document $collection, Document $attribute, string $projectId): void
|
||||
{
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
$collectionId = $collection->getId();
|
||||
$key = $attribute->getAttribute('key', '');
|
||||
|
||||
$collectionId = $attribute->getCollection();
|
||||
$id = $attribute->getAttribute('$id');
|
||||
try {
|
||||
if(!$dbForExternal->deleteAttribute($collectionId, $key)) {
|
||||
throw new Exception('Failed to delete Attribute');
|
||||
}
|
||||
|
||||
$success = $dbForExternal->deleteAttribute($collectionId, $id);
|
||||
$dbForInternal->deleteDocument('attributes', $attribute->getId());
|
||||
} catch (\Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
$dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed'));
|
||||
}
|
||||
|
||||
$dbForInternal->deleteCachedDocument('collections', $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function createIndex($index, $projectId): void
|
||||
protected function createIndex(Document $collection, Document $index, string $projectId): void
|
||||
{
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $index->getCollection();
|
||||
$id = $index->getAttribute('$id', '');
|
||||
$collectionId = $collection->getId();
|
||||
$key = $index->getAttribute('key', '');
|
||||
$type = $index->getAttribute('type', '');
|
||||
$attributes = $index->getAttribute('attributes', []);
|
||||
$lengths = $index->getAttribute('lengths', []);
|
||||
$orders = $index->getAttribute('orders', []);
|
||||
|
||||
$success = $dbForExternal->createIndex($collectionId, $id, $type, $attributes, $lengths, $orders);
|
||||
if ($success) {
|
||||
$dbForExternal->removeIndexInQueue($collectionId, $id);
|
||||
try {
|
||||
if(!$dbForExternal->createIndex($collectionId, $key, $type, $attributes, $lengths, $orders)) {
|
||||
throw new Exception('Failed to create Index');
|
||||
}
|
||||
$dbForInternal->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available'));
|
||||
} catch (\Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
$dbForInternal->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'failed'));
|
||||
}
|
||||
|
||||
$dbForInternal->deleteCachedDocument('collections', $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteIndex($index, $projectId): void
|
||||
protected function deleteIndex(Document $collection, Document $index, string $projectId): void
|
||||
{
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $index->getCollection();
|
||||
$id = $index->getAttribute('$id');
|
||||
$collectionId = $collection->getId();
|
||||
$key = $index->getAttribute('key');
|
||||
|
||||
$success = $dbForExternal->deleteIndex($collectionId, $id);
|
||||
try {
|
||||
if(!$dbForExternal->deleteIndex($collectionId, $key)) {
|
||||
throw new Exception('Failed to delete Attribute');
|
||||
}
|
||||
|
||||
$dbForInternal->deleteDocument('indexes', $index->getId());
|
||||
} catch (\Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
$dbForInternal->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'failed'));
|
||||
}
|
||||
|
||||
$dbForInternal->deleteCachedDocument('collections', $collectionId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,21 @@ use Utopia\Abuse\Adapters\TimeLimit;
|
|||
use Utopia\CLI\Console;
|
||||
use Utopia\Audit\Audit;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Deletes V1 Worker');
|
||||
Console::success(APP_NAME.' deletes worker v1 has started'."\n");
|
||||
|
||||
class DeletesV1 extends Worker
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $args = [];
|
||||
|
||||
/**
|
||||
* @var Database
|
||||
*/
|
||||
protected $consoleDB = null;
|
||||
|
||||
public function init(): void
|
||||
|
@ -33,11 +39,14 @@ class DeletesV1 extends Worker
|
|||
|
||||
switch (strval($type)) {
|
||||
case DELETE_TYPE_DOCUMENT:
|
||||
$document = $this->args['document'] ?? '';
|
||||
$document = $this->args['document'] ?? [];
|
||||
$document = new Document($document);
|
||||
|
||||
switch ($document->getCollection()) {
|
||||
// TODO@kodumbeats define these as constants somewhere
|
||||
case 'collections':
|
||||
$this->deleteCollection($document, $projectId);
|
||||
break;
|
||||
case 'projects':
|
||||
$this->deleteProject($document);
|
||||
break;
|
||||
|
@ -72,7 +81,10 @@ class DeletesV1 extends Worker
|
|||
$document = new Document($this->args['document']);
|
||||
$this->deleteCertificates($document);
|
||||
break;
|
||||
|
||||
|
||||
case DELETE_TYPE_USAGE:
|
||||
$this->deleteUsageStats($this->args['timestamp1d'], $this->args['timestamp30m']);
|
||||
break;
|
||||
default:
|
||||
Console::error('No delete operation for type: '.$type);
|
||||
break;
|
||||
|
@ -82,12 +94,58 @@ class DeletesV1 extends Worker
|
|||
public function shutdown(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteCollection(Document $document, string $projectId): void
|
||||
{
|
||||
$collectionId = $document->getId();
|
||||
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$this->deleteByGroup('attributes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
|
||||
], $dbForInternal);
|
||||
|
||||
$this->deleteByGroup('indexes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
|
||||
], $dbForInternal);
|
||||
|
||||
$dbForExternal->deleteCollection($collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timestamp1d
|
||||
* @param int $timestamp30m
|
||||
*/
|
||||
protected function deleteUsageStats(int $timestamp1d, int $timestamp30m) {
|
||||
$this->deleteForProjectIds(function($projectId) use ($timestamp1d, $timestamp30m) {
|
||||
if (!($dbForInternal = $this->getInternalDB($projectId))) {
|
||||
throw new Exception('Failed to get projectDB for project '.$projectId);
|
||||
}
|
||||
|
||||
// Delete Usage stats
|
||||
$this->deleteByGroup('stats', [
|
||||
new Query('time', Query::TYPE_LESSER, [$timestamp1d]),
|
||||
new Query('period', Query::TYPE_EQUAL, ['1d']),
|
||||
], $dbForInternal);
|
||||
|
||||
$this->deleteByGroup('stats', [
|
||||
new Query('time', Query::TYPE_LESSER, [$timestamp30m]),
|
||||
new Query('period', Query::TYPE_EQUAL, ['30m']),
|
||||
], $dbForInternal);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteMemberships(Document $document, $projectId) {
|
||||
protected function deleteMemberships(Document $document, string $projectId): void
|
||||
{
|
||||
$teamId = $document->getAttribute('teamId', '');
|
||||
|
||||
// Delete Memberships
|
||||
|
@ -99,7 +157,7 @@ class DeletesV1 extends Worker
|
|||
/**
|
||||
* @param Document $document project document
|
||||
*/
|
||||
protected function deleteProject(Document $document)
|
||||
protected function deleteProject(Document $document): void
|
||||
{
|
||||
$projectId = $document->getId();
|
||||
// Delete all DBs
|
||||
|
@ -118,7 +176,7 @@ class DeletesV1 extends Worker
|
|||
* @param Document $document user document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteUser(Document $document, $projectId)
|
||||
protected function deleteUser(Document $document, string $projectId): void
|
||||
{
|
||||
$userId = $document->getId();
|
||||
|
||||
|
@ -143,9 +201,9 @@ class DeletesV1 extends Worker
|
|||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteExecutionLogs($timestamp)
|
||||
protected function deleteExecutionLogs(int $timestamp): void
|
||||
{
|
||||
$this->deleteForProjectIds(function($projectId) use ($timestamp) {
|
||||
$this->deleteForProjectIds(function(string $projectId) use ($timestamp) {
|
||||
if (!($dbForInternal = $this->getInternalDB($projectId))) {
|
||||
throw new Exception('Failed to get projectDB for project '.$projectId);
|
||||
}
|
||||
|
@ -160,7 +218,7 @@ class DeletesV1 extends Worker
|
|||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteAbuseLogs($timestamp)
|
||||
protected function deleteAbuseLogs(int $timestamp): void
|
||||
{
|
||||
if($timestamp == 0) {
|
||||
throw new Exception('Failed to delete audit logs. No timestamp provided');
|
||||
|
@ -180,7 +238,7 @@ class DeletesV1 extends Worker
|
|||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteAuditLogs($timestamp)
|
||||
protected function deleteAuditLogs(int $timestamp): void
|
||||
{
|
||||
if($timestamp == 0) {
|
||||
throw new Exception('Failed to delete audit logs. No timestamp provided');
|
||||
|
@ -198,7 +256,7 @@ class DeletesV1 extends Worker
|
|||
* @param Document $document function document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteFunction(Document $document, $projectId)
|
||||
protected function deleteFunction(Document $document, string $projectId): void
|
||||
{
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$device = new Local(APP_STORAGE_FUNCTIONS.'/app-'.$projectId);
|
||||
|
@ -255,7 +313,7 @@ class DeletesV1 extends Worker
|
|||
/**
|
||||
* @param callable $callback
|
||||
*/
|
||||
protected function deleteForProjectIds(callable $callback)
|
||||
protected function deleteForProjectIds(callable $callback): void
|
||||
{
|
||||
$count = 0;
|
||||
$chunk = 0;
|
||||
|
@ -266,12 +324,12 @@ class DeletesV1 extends Worker
|
|||
$executionStart = \microtime(true);
|
||||
|
||||
while($sum === $limit) {
|
||||
$chunk++;
|
||||
|
||||
Authorization::disable();
|
||||
$projects = $this->getConsoleDB()->find('projects', [], $limit);
|
||||
$projects = $this->getConsoleDB()->find('projects', [], $limit, ($chunk * $limit));
|
||||
Authorization::reset();
|
||||
|
||||
$chunk++;
|
||||
|
||||
$projectIds = array_map (function ($project) {
|
||||
return $project->getId();
|
||||
}, $projects);
|
||||
|
@ -295,7 +353,7 @@ class DeletesV1 extends Worker
|
|||
* @param Database $database
|
||||
* @param callable $callback
|
||||
*/
|
||||
protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null)
|
||||
protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
|
||||
{
|
||||
$count = 0;
|
||||
$chunk = 0;
|
||||
|
@ -331,9 +389,8 @@ class DeletesV1 extends Worker
|
|||
|
||||
/**
|
||||
* @param Document $document certificates document
|
||||
* @return Database
|
||||
*/
|
||||
protected function deleteCertificates(Document $document)
|
||||
protected function deleteCertificates(Document $document): void
|
||||
{
|
||||
$domain = $document->getAttribute('domain');
|
||||
$directory = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
|
|
|
@ -13,7 +13,7 @@ use Utopia\Database\Database;
|
|||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Runtime::enableCoroutine(0);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use Utopia\App;
|
|||
use Utopia\CLI\Console;
|
||||
use Utopia\Locale\Locale;
|
||||
|
||||
require_once __DIR__ . '/../workers.php';
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
Console::title('Mails V1 Worker');
|
||||
Console::success(APP_NAME . ' mails worker v1 has started' . "\n");
|
||||
|
|
|
@ -4,7 +4,7 @@ use Appwrite\Resque\Worker;
|
|||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Webhooks V1 Worker');
|
||||
Console::success(APP_NAME.' webhooks worker v1 has started');
|
||||
|
|
3
bin/usage
Executable file
3
bin/usage
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
php /usr/src/code/app/cli.php usage $@
|
|
@ -38,14 +38,14 @@
|
|||
"appwrite/php-clamav": "1.1.*",
|
||||
"appwrite/php-runtimes": "0.4.*",
|
||||
|
||||
"utopia-php/framework": "0.17.*",
|
||||
"utopia-php/framework": "0.18.*",
|
||||
"utopia-php/abuse": "0.6.*",
|
||||
"utopia-php/analytics": "0.2.*",
|
||||
"utopia-php/audit": "0.6.*",
|
||||
"utopia-php/cache": "0.4.*",
|
||||
"utopia-php/cli": "0.11.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.7.*",
|
||||
"utopia-php/database": "0.10.0",
|
||||
"utopia-php/locale": "0.4.*",
|
||||
"utopia-php/registry": "0.5.*",
|
||||
"utopia-php/preloader": "0.2.*",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"utopia-php/swoole": "0.2.*",
|
||||
"utopia-php/storage": "0.5.*",
|
||||
"utopia-php/image": "0.5.*",
|
||||
|
||||
|
||||
"resque/php-resque": "1.3.6",
|
||||
"matomo/device-detector": "4.2.3",
|
||||
"dragonmantank/cron-expression": "3.1.0",
|
||||
|
|
187
composer.lock
generated
187
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "7de5dc8a9fe3cbc14696c685d1cdddee",
|
||||
"content-hash": "dfb8fa19daa736b3687617c98f309983",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -248,16 +248,16 @@
|
|||
},
|
||||
{
|
||||
"name": "chillerlan/php-settings-container",
|
||||
"version": "2.1.1",
|
||||
"version": "2.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chillerlan/php-settings-container.git",
|
||||
"reference": "98ccc1b31b31a53bcb563465c4961879b2b93096"
|
||||
"reference": "ec834493a88682dd69652a1eeaf462789ed0c5f5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/98ccc1b31b31a53bcb563465c4961879b2b93096",
|
||||
"reference": "98ccc1b31b31a53bcb563465c4961879b2b93096",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/ec834493a88682dd69652a1eeaf462789ed0c5f5",
|
||||
"reference": "ec834493a88682dd69652a1eeaf462789ed0c5f5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -307,7 +307,7 @@
|
|||
"type": "ko_fi"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-06T15:57:03+00:00"
|
||||
"time": "2021-09-06T15:17:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "colinmollenhour/credis",
|
||||
|
@ -355,16 +355,16 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
"version": "1.11.99.2",
|
||||
"version": "1.11.99.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/package-versions-deprecated.git",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c"
|
||||
"reference": "b174585d1fe49ceed21928a945138948cb394600"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600",
|
||||
"reference": "b174585d1fe49ceed21928a945138948cb394600",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -408,7 +408,7 @@
|
|||
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/package-versions-deprecated/issues",
|
||||
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2"
|
||||
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -424,7 +424,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-05-24T07:46:03+00:00"
|
||||
"time": "2021-09-13T08:41:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
|
@ -1666,22 +1666,22 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "4cd9c16610f7398d2e1737663ef682fa721ae736"
|
||||
"reference": "d63e928c2c50b367495a499a85ba9806ee274c5e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/4cd9c16610f7398d2e1737663ef682fa721ae736",
|
||||
"reference": "4cd9c16610f7398d2e1737663ef682fa721ae736",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/d63e928c2c50b367495a499a85ba9806ee274c5e",
|
||||
"reference": "d63e928c2c50b367495a499a85ba9806ee274c5e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pdo": "*",
|
||||
"php": ">=7.4",
|
||||
"utopia-php/database": "0.7.*"
|
||||
"utopia-php/database": ">=0.6 <1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.4",
|
||||
|
@ -1713,9 +1713,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.6.2"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.6.3"
|
||||
},
|
||||
"time": "2021-08-13T07:52:34+00:00"
|
||||
"time": "2021-08-16T18:38:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
|
@ -1774,22 +1774,22 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "2ec39a53eb98a5f9d230550ad56c7c04de5d77df"
|
||||
"reference": "d79b467fbc7d03e5e02f12cdeb08761507a60ca0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/2ec39a53eb98a5f9d230550ad56c7c04de5d77df",
|
||||
"reference": "2ec39a53eb98a5f9d230550ad56c7c04de5d77df",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/d79b467fbc7d03e5e02f12cdeb08761507a60ca0",
|
||||
"reference": "d79b467fbc7d03e5e02f12cdeb08761507a60ca0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pdo": "*",
|
||||
"php": ">=7.4",
|
||||
"utopia-php/database": "0.7.*"
|
||||
"utopia-php/database": ">=0.6 <1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
|
@ -1821,9 +1821,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.6.2"
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.6.3"
|
||||
},
|
||||
"time": "2021-08-13T08:05:20+00:00"
|
||||
"time": "2021-08-16T18:49:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
|
@ -1984,16 +1984,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.7.0",
|
||||
"version": "0.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "46c4a99347397e362a9429826e1888b0aefb2056"
|
||||
"reference": "b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/46c4a99347397e362a9429826e1888b0aefb2056",
|
||||
"reference": "46c4a99347397e362a9429826e1888b0aefb2056",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8",
|
||||
"reference": "b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2041,9 +2041,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.7.0"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.10.0"
|
||||
},
|
||||
"time": "2021-08-10T19:09:58+00:00"
|
||||
"time": "2021-10-04T17:23:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
@ -2101,16 +2101,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.17.3",
|
||||
"version": "0.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/framework.git",
|
||||
"reference": "0274f6b3e49db2af0d702edf278ec7504dc99878"
|
||||
"reference": "f577522a5eb8009967b893fb7ad4ee70d3f7c0db"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/framework/zipball/0274f6b3e49db2af0d702edf278ec7504dc99878",
|
||||
"reference": "0274f6b3e49db2af0d702edf278ec7504dc99878",
|
||||
"url": "https://api.github.com/repos/utopia-php/framework/zipball/f577522a5eb8009967b893fb7ad4ee70d3f7c0db",
|
||||
"reference": "f577522a5eb8009967b893fb7ad4ee70d3f7c0db",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2144,9 +2144,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/framework/issues",
|
||||
"source": "https://github.com/utopia-php/framework/tree/0.17.3"
|
||||
"source": "https://github.com/utopia-php/framework/tree/0.18.0"
|
||||
},
|
||||
"time": "2021-08-03T13:57:01+00:00"
|
||||
"time": "2021-08-19T04:58:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
|
@ -2582,16 +2582,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "amphp/amp",
|
||||
"version": "v2.6.0",
|
||||
"version": "v2.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/amphp/amp.git",
|
||||
"reference": "caa95edeb1ca1bf7532e9118ede4a3c3126408cc"
|
||||
"reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/amphp/amp/zipball/caa95edeb1ca1bf7532e9118ede4a3c3126408cc",
|
||||
"reference": "caa95edeb1ca1bf7532e9118ede4a3c3126408cc",
|
||||
"url": "https://api.github.com/repos/amphp/amp/zipball/c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae",
|
||||
"reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2659,7 +2659,7 @@
|
|||
"support": {
|
||||
"irc": "irc://irc.freenode.org/amphp",
|
||||
"issues": "https://github.com/amphp/amp/issues",
|
||||
"source": "https://github.com/amphp/amp/tree/v2.6.0"
|
||||
"source": "https://github.com/amphp/amp/tree/v2.6.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2667,7 +2667,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-16T20:06:06+00:00"
|
||||
"time": "2021-09-23T18:43:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "amphp/byte-stream",
|
||||
|
@ -3389,16 +3389,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.12.0",
|
||||
"version": "v4.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "6608f01670c3cc5079e18c1dab1104e002579143"
|
||||
"reference": "50953a2691a922aa1769461637869a0a2faa3f53"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143",
|
||||
"reference": "6608f01670c3cc5079e18c1dab1104e002579143",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53",
|
||||
"reference": "50953a2691a922aa1769461637869a0a2faa3f53",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3439,9 +3439,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0"
|
||||
},
|
||||
"time": "2021-07-21T10:44:31+00:00"
|
||||
"time": "2021-09-20T12:20:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openlss/lib-array2xml",
|
||||
|
@ -3718,16 +3718,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0"
|
||||
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
|
||||
"reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae",
|
||||
"reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3735,7 +3735,8 @@
|
|||
"phpdocumentor/reflection-common": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-tokenizer": "*"
|
||||
"ext-tokenizer": "*",
|
||||
"psalm/phar": "^4.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -3761,39 +3762,39 @@
|
|||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0"
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1"
|
||||
},
|
||||
"time": "2020-09-17T18:55:26+00:00"
|
||||
"time": "2021-10-02T14:08:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.13.0",
|
||||
"version": "1.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "be1996ed8adc35c3fd795488a653f4b518be70ea"
|
||||
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea",
|
||||
"reference": "be1996ed8adc35c3fd795488a653f4b518be70ea",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
|
||||
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.2",
|
||||
"php": "^7.2 || ~8.0, <8.1",
|
||||
"php": "^7.2 || ~8.0, <8.2",
|
||||
"phpdocumentor/reflection-docblock": "^5.2",
|
||||
"sebastian/comparator": "^3.0 || ^4.0",
|
||||
"sebastian/recursion-context": "^3.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^6.0",
|
||||
"phpspec/phpspec": "^6.0 || ^7.0",
|
||||
"phpunit/phpunit": "^8.0 || ^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.11.x-dev"
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -3828,29 +3829,29 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||
"source": "https://github.com/phpspec/prophecy/tree/1.13.0"
|
||||
"source": "https://github.com/phpspec/prophecy/tree/1.14.0"
|
||||
},
|
||||
"time": "2021-03-17T13:42:18+00:00"
|
||||
"time": "2021-09-10T09:02:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.6",
|
||||
"version": "9.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "f6293e1b30a2354e8428e004689671b83871edde"
|
||||
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde",
|
||||
"reference": "f6293e1b30a2354e8428e004689671b83871edde",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218",
|
||||
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.10.2",
|
||||
"nikic/php-parser": "^4.12.0",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-file-iterator": "^3.0.3",
|
||||
"phpunit/php-text-template": "^2.0.2",
|
||||
|
@ -3899,7 +3900,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3907,7 +3908,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-28T07:26:59+00:00"
|
||||
"time": "2021-09-17T05:39:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -5319,16 +5320,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.3.6",
|
||||
"version": "v5.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2"
|
||||
"reference": "8b1008344647462ae6ec57559da166c2bfa5e16a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
|
||||
"reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a",
|
||||
"reference": "8b1008344647462ae6ec57559da166c2bfa5e16a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -5398,7 +5399,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v5.3.6"
|
||||
"source": "https://github.com/symfony/console/tree/v5.3.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -5414,7 +5415,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-27T19:10:22+00:00"
|
||||
"time": "2021-08-25T20:02:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -5888,16 +5889,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v5.3.3",
|
||||
"version": "v5.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1"
|
||||
"reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1",
|
||||
"reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5",
|
||||
"reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -5951,7 +5952,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v5.3.3"
|
||||
"source": "https://github.com/symfony/string/tree/v5.3.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -5967,7 +5968,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-06-27T11:44:38+00:00"
|
||||
"time": "2021-08-26T08:00:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
@ -6021,16 +6022,16 @@
|
|||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v2.14.6",
|
||||
"version": "v2.14.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "27e5cf2b05e3744accf39d4c68a3235d9966d260"
|
||||
"reference": "8e202327ee1ed863629de9b18a5ec70ac614d88f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/27e5cf2b05e3744accf39d4c68a3235d9966d260",
|
||||
"reference": "27e5cf2b05e3744accf39d4c68a3235d9966d260",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/8e202327ee1ed863629de9b18a5ec70ac614d88f",
|
||||
"reference": "8e202327ee1ed863629de9b18a5ec70ac614d88f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -6040,7 +6041,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"psr/container": "^1.0",
|
||||
"symfony/phpunit-bridge": "^4.4.9|^5.0.9"
|
||||
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -6084,7 +6085,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v2.14.6"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v2.14.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -6096,7 +6097,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-05-16T12:12:47+00:00"
|
||||
"time": "2021-09-17T08:39:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vimeo/psalm",
|
||||
|
@ -6278,5 +6279,5 @@
|
|||
"platform-overrides": {
|
||||
"php": "8.0"
|
||||
},
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.1.0"
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ version: '3'
|
|||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.3
|
||||
image: traefik:2.5
|
||||
container_name: appwrite-traefik
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
|
@ -73,7 +73,6 @@ services:
|
|||
- mariadb
|
||||
- redis
|
||||
# - clamav
|
||||
- influxdb
|
||||
entrypoint:
|
||||
- php
|
||||
- -e
|
||||
|
@ -112,8 +111,6 @@ services:
|
|||
- _APP_SMTP_USERNAME
|
||||
- _APP_SMTP_PASSWORD
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_INFLUXDB_HOST
|
||||
- _APP_INFLUXDB_PORT
|
||||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
|
@ -214,6 +211,7 @@ services:
|
|||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
# - ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
|
@ -348,6 +346,37 @@ services:
|
|||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
|
||||
appwrite-usage:
|
||||
entrypoint:
|
||||
- php
|
||||
- -e
|
||||
- /usr/src/code/app/cli.php
|
||||
- usage
|
||||
container_name: appwrite-usage
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- DEBUG=false
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
- ./dev:/usr/local/dev
|
||||
depends_on:
|
||||
- influxdb
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_INFLUXDB_HOST
|
||||
- _APP_INFLUXDB_PORT
|
||||
- _APP_USAGE_SYNC_INTERVAL
|
||||
|
||||
appwrite-schedule:
|
||||
entrypoint: schedule
|
||||
container_name: appwrite-schedule
|
||||
|
@ -381,7 +410,7 @@ services:
|
|||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=user
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
command: 'mysqld --innodb-flush-method=fsync --wait_timeout=86400' # add ' --query_cache_size=0' for DB tests
|
||||
command: 'mysqld --innodb-flush-method=fsync' # add ' --query_cache_size=0' for DB tests
|
||||
# command: mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile0.bu && mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/ib_logfile1.bu
|
||||
|
||||
# smtp:
|
||||
|
@ -399,6 +428,8 @@ services:
|
|||
redis:
|
||||
image: redis:6.0-alpine
|
||||
container_name: appwrite-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.create('email@example.com', 'password');
|
||||
let promise = sdk.account.create('', 'email@example.com', 'password');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.createDocument('[COLLECTION_ID]', {});
|
||||
let promise = sdk.database.createDocument('[COLLECTION_ID]', '', {});
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.storage.createFile(document.getElementById('uploader').files[0]);
|
||||
let promise = sdk.storage.createFile('', document.getElementById('uploader').files[0]);
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.teams.create('[NAME]');
|
||||
let promise = sdk.teams.create('', '[NAME]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.createCollection('', '[NAME]', '', '');
|
||||
let promise = sdk.database.createCollection('', '[NAME]', 'document', '', '');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.createUrlAttribute('[COLLECTION_ID]', '', null, false);
|
||||
let promise = sdk.database.createUrlAttribute('[COLLECTION_ID]', '', false);
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.listCollectionLogs('[COLLECTION_ID]');
|
||||
let promise = sdk.database.getCollectionLogs('[COLLECTION_ID]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
let sdk = new Appwrite();
|
||||
|
||||
sdk
|
||||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.listCollectionLogs('[COLLECTION_ID]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.updateCollection('[COLLECTION_ID]', '[NAME]');
|
||||
let promise = sdk.database.updateCollection('[COLLECTION_ID]', '[NAME]', 'document');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
65
public/dist/scripts/app-all.js
vendored
65
public/dist/scripts/app-all.js
vendored
|
@ -88,22 +88,27 @@ if(typeof size!=='undefined'){payload['size']=size;}
|
|||
if(typeof margin!=='undefined'){payload['margin']=margin;}
|
||||
if(typeof download!=='undefined'){payload['download']=download;}
|
||||
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
|
||||
return uri;}};this.database={listCollections:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/database/collections';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
return uri;}};this.database={listCollections:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/database/collections';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createCollection:(collectionId,name,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createCollection:(collectionId,name,permission,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof permission==='undefined'){throw new AppwriteException('Missing required parameter: "permission"');}
|
||||
if(typeof read==='undefined'){throw new AppwriteException('Missing required parameter: "read"');}
|
||||
if(typeof write==='undefined'){throw new AppwriteException('Missing required parameter: "write"');}
|
||||
let path='/database/collections';let payload={};if(typeof collectionId!=='undefined'){payload['collectionId']=collectionId;}
|
||||
if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof permission!=='undefined'){payload['permission']=permission;}
|
||||
if(typeof read!=='undefined'){payload['read']=read;}
|
||||
if(typeof write!=='undefined'){payload['write']=write;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateCollection:(collectionId,name,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateCollection:(collectionId,name,permission,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof permission==='undefined'){throw new AppwriteException('Missing required parameter: "permission"');}
|
||||
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof permission!=='undefined'){payload['permission']=permission;}
|
||||
if(typeof read!=='undefined'){payload['read']=read;}
|
||||
if(typeof write!=='undefined'){payload['write']=write;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
|
@ -156,12 +161,10 @@ if(typeof size!=='undefined'){payload['size']=size;}
|
|||
if(typeof required!=='undefined'){payload['required']=required;}
|
||||
if(typeof xdefault!=='undefined'){payload['xdefault']=xdefault;}
|
||||
if(typeof array!=='undefined'){payload['array']=array;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),createUrlAttribute:(collectionId,attributeId,size,required,xdefault,array)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),createUrlAttribute:(collectionId,attributeId,required,xdefault,array)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof attributeId==='undefined'){throw new AppwriteException('Missing required parameter: "attributeId"');}
|
||||
if(typeof size==='undefined'){throw new AppwriteException('Missing required parameter: "size"');}
|
||||
if(typeof required==='undefined'){throw new AppwriteException('Missing required parameter: "required"');}
|
||||
let path='/database/collections/{collectionId}/attributes/url'.replace('{collectionId}',collectionId);let payload={};if(typeof attributeId!=='undefined'){payload['attributeId']=attributeId;}
|
||||
if(typeof size!=='undefined'){payload['size']=size;}
|
||||
if(typeof required!=='undefined'){payload['required']=required;}
|
||||
if(typeof xdefault!=='undefined'){payload['xdefault']=xdefault;}
|
||||
if(typeof array!=='undefined'){payload['array']=array;}
|
||||
|
@ -169,10 +172,11 @@ const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{
|
|||
if(typeof attributeId==='undefined'){throw new AppwriteException('Missing required parameter: "attributeId"');}
|
||||
let path='/database/collections/{collectionId}/attributes/{attributeId}'.replace('{collectionId}',collectionId).replace('{attributeId}',attributeId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteAttribute:(collectionId,attributeId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof attributeId==='undefined'){throw new AppwriteException('Missing required parameter: "attributeId"');}
|
||||
let path='/database/collections/{collectionId}/attributes/{attributeId}'.replace('{collectionId}',collectionId).replace('{attributeId}',attributeId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listDocuments:(collectionId,queries,limit,offset,orderAttributes,orderTypes)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/attributes/{attributeId}'.replace('{collectionId}',collectionId).replace('{attributeId}',attributeId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listDocuments:(collectionId,queries,limit,offset,after,orderAttributes,orderTypes)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/documents'.replace('{collectionId}',collectionId);let payload={};if(typeof queries!=='undefined'){payload['queries']=queries;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderAttributes!=='undefined'){payload['orderAttributes']=orderAttributes;}
|
||||
if(typeof orderTypes!=='undefined'){payload['orderTypes']=orderTypes;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createDocument:(collectionId,documentId,data,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
|
@ -201,14 +205,15 @@ let path='/database/collections/{collectionId}/indexes'.replace('{collectionId}'
|
|||
if(typeof type!=='undefined'){payload['type']=type;}
|
||||
if(typeof attributes!=='undefined'){payload['attributes']=attributes;}
|
||||
if(typeof orders!=='undefined'){payload['orders']=orders;}
|
||||
console.log(collectionId,indexId,type,attributes,orders);const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listCollectionLogs:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/logs'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
let path='/database/collections/{collectionId}/logs'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(functionId,name,execute,runtime,vars,events,schedule,timeout)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
|
@ -233,9 +238,10 @@ if(typeof events!=='undefined'){payload['events']=events;}
|
|||
if(typeof schedule!=='undefined'){payload['schedule']=schedule;}
|
||||
if(typeof timeout!=='undefined'){payload['timeout']=timeout;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(functionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listExecutions:(functionId,limit,offset)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listExecutions:(functionId,limit,offset,after)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createExecution:(functionId,data)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(typeof data!=='undefined'){payload['data']=data;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getExecution:(functionId,executionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
|
@ -243,10 +249,11 @@ if(typeof executionId==='undefined'){throw new AppwriteException('Missing requir
|
|||
let path='/functions/{functionId}/executions/{executionId}'.replace('{functionId}',functionId).replace('{executionId}',executionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateTag:(functionId,tag)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
if(typeof tag==='undefined'){throw new AppwriteException('Missing required parameter: "tag"');}
|
||||
let path='/functions/{functionId}/tag'.replace('{functionId}',functionId);let payload={};if(typeof tag!=='undefined'){payload['tag']=tag;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listTags:(functionId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listTags:(functionId,search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTag:(functionId,command,code)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
if(typeof command==='undefined'){throw new AppwriteException('Missing required parameter: "command"');}
|
||||
|
@ -259,9 +266,10 @@ let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionI
|
|||
if(typeof tagId==='undefined'){throw new AppwriteException('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionId).replace('{tagId}',tagId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getUsage:(functionId,range)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/usage'.replace('{functionId}',functionId);let payload={};if(typeof range!=='undefined'){payload['range']=range;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.health={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/health';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getAntiVirus:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/anti-virus';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCache:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/cache';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getDB:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/db';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueCertificates:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/certificates';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueFunctions:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/functions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueUsage:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/usage';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueWebhooks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/webhooks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getStorageLocal:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/storage/local';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getTime:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/time';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.locale={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getContinents:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/continents';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountries:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesEU:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/eu';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesPhones:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/phones';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCurrencies:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/currencies';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getLanguages:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/languages';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.projects={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.health={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/health';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getAntiVirus:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/anti-virus';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCache:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/cache';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getDB:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/db';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueCertificates:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/certificates';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueFunctions:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/functions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueUsage:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/usage';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueWebhooks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/webhooks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getStorageLocal:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/storage/local';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getTime:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/time';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.locale={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getContinents:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/continents';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountries:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesEU:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/eu';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesPhones:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/phones';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCurrencies:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/currencies';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getLanguages:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/languages';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.projects={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(projectId,name,teamId,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId)=>__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"');}
|
||||
|
@ -387,9 +395,10 @@ if(typeof httpUser!=='undefined'){payload['httpUser']=httpUser;}
|
|||
if(typeof httpPass!=='undefined'){payload['httpPass']=httpPass;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteWebhook:(projectId,webhookId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
if(typeof webhookId==='undefined'){throw new AppwriteException('Missing required parameter: "webhookId"');}
|
||||
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.storage={listFiles:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/files';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.storage={listFiles:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/files';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createFile:(fileId,file,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
|
||||
if(typeof file==='undefined'){throw new AppwriteException('Missing required parameter: "file"');}
|
||||
|
@ -421,9 +430,10 @@ if(typeof output!=='undefined'){payload['output']=output;}
|
|||
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
|
||||
return uri;},getFileView:(fileId)=>{if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
|
||||
let path='/storage/files/{fileId}/view'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
|
||||
return uri;}};this.teams={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/teams';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
return uri;}};this.teams={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/teams';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(teamId,name,roles)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
|
@ -435,10 +445,11 @@ let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=n
|
|||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(teamId)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getMemberships:(teamId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getMemberships:(teamId,search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
let path='/teams/{teamId}/memberships'.replace('{teamId}',teamId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createMembership:(teamId,email,roles,url,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
|
||||
|
@ -462,9 +473,10 @@ if(typeof userId==='undefined'){throw new AppwriteException('Missing required pa
|
|||
if(typeof secret==='undefined'){throw new AppwriteException('Missing required parameter: "secret"');}
|
||||
let path='/teams/{teamId}/memberships/{membershipId}/status'.replace('{teamId}',teamId).replace('{membershipId}',membershipId);let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
|
||||
if(typeof secret!=='undefined'){payload['secret']=secret;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};this.users={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/users';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};this.users={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/users';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(userId,email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
|
||||
|
@ -475,8 +487,17 @@ if(typeof password!=='undefined'){payload['password']=password;}
|
|||
if(typeof name!=='undefined'){payload['name']=name;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),delete:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getLogs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}/logs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getPrefs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateEmail:(userId,email)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
|
||||
let path='/users/{userId}/email'.replace('{userId}',userId);let payload={};if(typeof email!=='undefined'){payload['email']=email;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getLogs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}/logs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateName:(userId,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
let path='/users/{userId}/name'.replace('{userId}',userId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updatePassword:(userId,password)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
|
||||
let path='/users/{userId}/password'.replace('{userId}',userId);let payload={};if(typeof password!=='undefined'){payload['password']=password;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getPrefs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePrefs:(userId,prefs)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof prefs==='undefined'){throw new AppwriteException('Missing required parameter: "prefs"');}
|
||||
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};if(typeof prefs!=='undefined'){payload['prefs']=prefs;}
|
||||
|
@ -2128,7 +2149,7 @@ result+'")": '+
|
|||
error);}
|
||||
if(debug){console.info("debug-ls-if result:",result);}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility="hidden";element.style.display="none";}else{element.style.removeProperty("display");element.style.removeProperty("visibility");}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}},});window.ls.container.get("view").add({selector:"data-ls-loop",template:false,nested:false,controller:function(element,view,container,filter,window,expression){let expr=expression.parse(element.getAttribute("data-ls-loop"));let as=element.getAttribute("data-ls-as");let filterName=element.getAttribute("data-ls-filter");let key=element.getAttribute("data-ls-key")||"$index";let prefix=element.getAttribute("data-ls-prefix")||null;let postfix=element.getAttribute("data-ls-postfix")||null;let limit=parseInt(expression.parse(element.getAttribute("data-ls-limit")||"")||-1);let debug=element.getAttribute("data-debug")||false;let echo=function(){let array=container.path(expr);let counter=0;array=!array?[]:array;if(filterName){array=filter.apply(filterName,array);console.log(array);}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}},});window.ls.container.get("view").add({selector:"data-ls-loop",template:false,nested:false,controller:function(element,view,container,filter,window,expression){let expr=expression.parse(element.getAttribute("data-ls-loop"));let as=element.getAttribute("data-ls-as");let filterName=element.getAttribute("data-ls-filter");let key=element.getAttribute("data-ls-key")||"$index";let prefix=element.getAttribute("data-ls-prefix")||null;let postfix=element.getAttribute("data-ls-postfix")||null;let limit=parseInt(expression.parse(element.getAttribute("data-ls-limit")||"")||-1);let debug=element.getAttribute("data-debug")||false;let echo=function(){let array=container.path(expr);let counter=0;array=!array?[]:array;if(filterName){array=filter.apply(filterName,array);}
|
||||
let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
if(array instanceof Array&&typeof array!=="object"){throw new Error("Reference value must be array or object. "+typeof array+" given");}
|
||||
let children=[];element.$lsSkip=true;element.style.visibility=0===array.length&&element.style.visibility==""?"hidden":"visible";if(prefix){prefixElement=document.getElementById(prefix);let html=prefixElement.innerHTML;prefixElement=template.cloneNode(true);if(prefixElement){prefixElement.innerHTML=html;element.appendChild(prefixElement);view.render(prefixElement);}}
|
||||
|
@ -2313,7 +2334,7 @@ return'';}).add("runtimeLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUN
|
|||
return'';}).add("runtimeVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;}
|
||||
return'';}).add("indexAttributes",function($value){let output='';for(let i=0;i<$value.attributes.length;i++){output+=$value.attributes[i]+' ('+$value.orders[i]+'), '}
|
||||
return output.slice(0,-2);}).add("collectionAttributes",function($value){if(!Array.isArray($value)){return[];}
|
||||
$value.unshift({$id:'$id'});return $value;}).add("documentAttribute",function($value,attribute){if($value[attribute.$id]){return $value[attribute.$id];}
|
||||
$value.unshift({$id:'$id'});return $value;}).add("documentAttribute",function($value,attribute){if($value[attribute.key]){return $value[attribute.key];}
|
||||
return null;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);}
|
||||
let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";}
|
||||
return annotate(number,maxPlaces,forcePlaces,abbr);}
|
||||
|
@ -2391,8 +2412,8 @@ element.setAttribute("data-id-type",idType);info.innerHTML="Appwrite will genera
|
|||
button.className=idType=="custom"?"icon-shuffle copy":"icon-edit copy";}
|
||||
const syncEditorWithID=function(event){if(element.value!=='unique()'||idType!='auto'){writer.value=element.value;}
|
||||
if(idType=='auto'){element.value='unique()';}}
|
||||
const keypress=function(e){const key=e.which||e.keyCode;const ZERO=48;const NINE=57;const SMALL_A=97;const SMALL_Z=122;const CAPITAL_A=65;const CAPITAL_Z=90;const UNDERSCORE=95;const isNotValidDigit=key<ZERO||key>NINE;const isNotValidSmallAlphabet=key<SMALL_A||key>SMALL_Z;const isNotValidCapitalAlphabet=key<CAPITAL_A||key>CAPITAL_Z;if(key==UNDERSCORE&&e.target.value.length==0){e.preventDefault();}
|
||||
if(key!=UNDERSCORE&&isNotValidDigit&&isNotValidSmallAlphabet&&isNotValidCapitalAlphabet){e.preventDefault();}}
|
||||
const keypress=function(e){const key=e.which||e.keyCode;const ZERO=48;const NINE=57;const SMALL_A=97;const SMALL_Z=122;const CAPITAL_A=65;const CAPITAL_Z=90;const UNDERSCORE=95;const HYPHEN=45;const PERIOD=46;const isNotValidDigit=key<ZERO||key>NINE;const isNotValidSmallAlphabet=key<SMALL_A||key>SMALL_Z;const isNotValidCapitalAlphabet=key<CAPITAL_A||key>CAPITAL_Z;const isNotValidFirstChar=(key===UNDERSCORE||key===HYPHEN||key===PERIOD);if(isNotValidFirstChar&&e.target.value.length==0){e.preventDefault();}
|
||||
if(key!=UNDERSCORE&&key!=HYPHEN&&key!=PERIOD&&isNotValidDigit&&isNotValidSmallAlphabet&&isNotValidCapitalAlphabet){e.preventDefault();}}
|
||||
syncEditorWithID();setIdType(idType);writer.addEventListener("change",function(event){element.value=writer.value;});writer.form.addEventListener('reset',function(event){const resetEvent=new Event('reset');element.dispatchEvent(resetEvent);});element.addEventListener('reset',function(event){idType=element.getAttribute('data-id-type');setIdType(idType);});writer.addEventListener('keypress',keypress);button.addEventListener("click",switchType);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-document",controller:function(element,container,search){var formsDocument=(element.dataset["formsDocument"]||'');var searchButton=(element.dataset["search"]||0);let path=container.scope(searchButton);element.addEventListener('click',function(){search.selected=element.value;search.path=path;document.dispatchEvent(new CustomEvent(formsDocument,{bubbles:false,cancelable:true}));});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-duplications",controller:function(element){let validate=function(element){let duplication=0;let form=element.form;for(let i=0;i<form.elements.length;i++){let field=form.elements[i];if(field.name===element.name&&field.value===element.value){duplication++;}}
|
||||
if(duplication>1){element.setCustomValidity("Duplicated value");}
|
||||
else{element.setCustomValidity("");}};element.addEventListener('change',function(event){validate(event.target)});element.addEventListener('focus',function(event){validate(event.target)});element.addEventListener('blur',function(event){validate(event.target)});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-document-preview",controller:function(element,container,search){element.addEventListener('change',function(){console.log(element.value);});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-filter",controller:function(document,container,expression,element,form,di){let name=element.dataset["formsFilter"]||"";let events=element.dataset["event"]||"";let serialize=function(obj,prefix){let str=[],p;for(p in obj){if(obj.hasOwnProperty(p)){let k=prefix?prefix+"["+p+"]":p,v=obj[p];if(v===""){continue;}
|
||||
|
|
57
public/dist/scripts/app-dep.js
vendored
57
public/dist/scripts/app-dep.js
vendored
|
@ -88,22 +88,27 @@ if(typeof size!=='undefined'){payload['size']=size;}
|
|||
if(typeof margin!=='undefined'){payload['margin']=margin;}
|
||||
if(typeof download!=='undefined'){payload['download']=download;}
|
||||
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
|
||||
return uri;}};this.database={listCollections:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/database/collections';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
return uri;}};this.database={listCollections:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/database/collections';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createCollection:(collectionId,name,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createCollection:(collectionId,name,permission,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof permission==='undefined'){throw new AppwriteException('Missing required parameter: "permission"');}
|
||||
if(typeof read==='undefined'){throw new AppwriteException('Missing required parameter: "read"');}
|
||||
if(typeof write==='undefined'){throw new AppwriteException('Missing required parameter: "write"');}
|
||||
let path='/database/collections';let payload={};if(typeof collectionId!=='undefined'){payload['collectionId']=collectionId;}
|
||||
if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof permission!=='undefined'){payload['permission']=permission;}
|
||||
if(typeof read!=='undefined'){payload['read']=read;}
|
||||
if(typeof write!=='undefined'){payload['write']=write;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateCollection:(collectionId,name,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateCollection:(collectionId,name,permission,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
if(typeof permission==='undefined'){throw new AppwriteException('Missing required parameter: "permission"');}
|
||||
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
if(typeof permission!=='undefined'){payload['permission']=permission;}
|
||||
if(typeof read!=='undefined'){payload['read']=read;}
|
||||
if(typeof write!=='undefined'){payload['write']=write;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
|
@ -156,12 +161,10 @@ if(typeof size!=='undefined'){payload['size']=size;}
|
|||
if(typeof required!=='undefined'){payload['required']=required;}
|
||||
if(typeof xdefault!=='undefined'){payload['xdefault']=xdefault;}
|
||||
if(typeof array!=='undefined'){payload['array']=array;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),createUrlAttribute:(collectionId,attributeId,size,required,xdefault,array)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),createUrlAttribute:(collectionId,attributeId,required,xdefault,array)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof attributeId==='undefined'){throw new AppwriteException('Missing required parameter: "attributeId"');}
|
||||
if(typeof size==='undefined'){throw new AppwriteException('Missing required parameter: "size"');}
|
||||
if(typeof required==='undefined'){throw new AppwriteException('Missing required parameter: "required"');}
|
||||
let path='/database/collections/{collectionId}/attributes/url'.replace('{collectionId}',collectionId);let payload={};if(typeof attributeId!=='undefined'){payload['attributeId']=attributeId;}
|
||||
if(typeof size!=='undefined'){payload['size']=size;}
|
||||
if(typeof required!=='undefined'){payload['required']=required;}
|
||||
if(typeof xdefault!=='undefined'){payload['xdefault']=xdefault;}
|
||||
if(typeof array!=='undefined'){payload['array']=array;}
|
||||
|
@ -169,10 +172,11 @@ const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{
|
|||
if(typeof attributeId==='undefined'){throw new AppwriteException('Missing required parameter: "attributeId"');}
|
||||
let path='/database/collections/{collectionId}/attributes/{attributeId}'.replace('{collectionId}',collectionId).replace('{attributeId}',attributeId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteAttribute:(collectionId,attributeId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof attributeId==='undefined'){throw new AppwriteException('Missing required parameter: "attributeId"');}
|
||||
let path='/database/collections/{collectionId}/attributes/{attributeId}'.replace('{collectionId}',collectionId).replace('{attributeId}',attributeId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listDocuments:(collectionId,queries,limit,offset,orderAttributes,orderTypes)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/attributes/{attributeId}'.replace('{collectionId}',collectionId).replace('{attributeId}',attributeId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listDocuments:(collectionId,queries,limit,offset,after,orderAttributes,orderTypes)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/documents'.replace('{collectionId}',collectionId);let payload={};if(typeof queries!=='undefined'){payload['queries']=queries;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderAttributes!=='undefined'){payload['orderAttributes']=orderAttributes;}
|
||||
if(typeof orderTypes!=='undefined'){payload['orderTypes']=orderTypes;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createDocument:(collectionId,documentId,data,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
|
@ -201,14 +205,15 @@ let path='/database/collections/{collectionId}/indexes'.replace('{collectionId}'
|
|||
if(typeof type!=='undefined'){payload['type']=type;}
|
||||
if(typeof attributes!=='undefined'){payload['attributes']=attributes;}
|
||||
if(typeof orders!=='undefined'){payload['orders']=orders;}
|
||||
console.log(collectionId,indexId,type,attributes,orders);const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteIndex:(collectionId,indexId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
if(typeof indexId==='undefined'){throw new AppwriteException('Missing required parameter: "indexId"');}
|
||||
let path='/database/collections/{collectionId}/indexes/{indexId}'.replace('{collectionId}',collectionId).replace('{indexId}',indexId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listCollectionLogs:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
|
||||
let path='/database/collections/{collectionId}/logs'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
let path='/database/collections/{collectionId}/logs'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(functionId,name,execute,runtime,vars,events,schedule,timeout)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
|
@ -233,9 +238,10 @@ if(typeof events!=='undefined'){payload['events']=events;}
|
|||
if(typeof schedule!=='undefined'){payload['schedule']=schedule;}
|
||||
if(typeof timeout!=='undefined'){payload['timeout']=timeout;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(functionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listExecutions:(functionId,limit,offset)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listExecutions:(functionId,limit,offset,after)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createExecution:(functionId,data)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(typeof data!=='undefined'){payload['data']=data;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getExecution:(functionId,executionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
|
@ -243,10 +249,11 @@ if(typeof executionId==='undefined'){throw new AppwriteException('Missing requir
|
|||
let path='/functions/{functionId}/executions/{executionId}'.replace('{functionId}',functionId).replace('{executionId}',executionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateTag:(functionId,tag)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
if(typeof tag==='undefined'){throw new AppwriteException('Missing required parameter: "tag"');}
|
||||
let path='/functions/{functionId}/tag'.replace('{functionId}',functionId);let payload={};if(typeof tag!=='undefined'){payload['tag']=tag;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listTags:(functionId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listTags:(functionId,search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTag:(functionId,command,code)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
if(typeof command==='undefined'){throw new AppwriteException('Missing required parameter: "command"');}
|
||||
|
@ -259,9 +266,10 @@ let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionI
|
|||
if(typeof tagId==='undefined'){throw new AppwriteException('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionId).replace('{tagId}',tagId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getUsage:(functionId,range)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/usage'.replace('{functionId}',functionId);let payload={};if(typeof range!=='undefined'){payload['range']=range;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.health={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/health';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getAntiVirus:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/anti-virus';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCache:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/cache';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getDB:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/db';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueCertificates:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/certificates';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueFunctions:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/functions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueUsage:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/usage';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueWebhooks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/webhooks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getStorageLocal:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/storage/local';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getTime:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/time';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.locale={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getContinents:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/continents';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountries:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesEU:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/eu';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesPhones:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/phones';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCurrencies:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/currencies';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getLanguages:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/languages';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.projects={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.health={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/health';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getAntiVirus:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/anti-virus';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCache:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/cache';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getDB:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/db';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueCertificates:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/certificates';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueFunctions:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/functions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueUsage:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/usage';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueWebhooks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/webhooks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getStorageLocal:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/storage/local';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getTime:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/time';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.locale={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getContinents:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/continents';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountries:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesEU:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/eu';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesPhones:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/phones';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCurrencies:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/currencies';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getLanguages:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/languages';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.projects={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(projectId,name,teamId,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId)=>__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"');}
|
||||
|
@ -387,9 +395,10 @@ if(typeof httpUser!=='undefined'){payload['httpUser']=httpUser;}
|
|||
if(typeof httpPass!=='undefined'){payload['httpPass']=httpPass;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteWebhook:(projectId,webhookId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
|
||||
if(typeof webhookId==='undefined'){throw new AppwriteException('Missing required parameter: "webhookId"');}
|
||||
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.storage={listFiles:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/files';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.storage={listFiles:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/files';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createFile:(fileId,file,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
|
||||
if(typeof file==='undefined'){throw new AppwriteException('Missing required parameter: "file"');}
|
||||
|
@ -421,9 +430,10 @@ if(typeof output!=='undefined'){payload['output']=output;}
|
|||
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
|
||||
return uri;},getFileView:(fileId)=>{if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
|
||||
let path='/storage/files/{fileId}/view'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
|
||||
return uri;}};this.teams={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/teams';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
return uri;}};this.teams={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/teams';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(teamId,name,roles)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
|
@ -435,10 +445,11 @@ let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=n
|
|||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(teamId)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getMemberships:(teamId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getMemberships:(teamId,search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
let path='/teams/{teamId}/memberships'.replace('{teamId}',teamId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createMembership:(teamId,email,roles,url,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
|
||||
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
|
||||
|
@ -462,9 +473,10 @@ if(typeof userId==='undefined'){throw new AppwriteException('Missing required pa
|
|||
if(typeof secret==='undefined'){throw new AppwriteException('Missing required parameter: "secret"');}
|
||||
let path='/teams/{teamId}/memberships/{membershipId}/status'.replace('{teamId}',teamId).replace('{membershipId}',membershipId);let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
|
||||
if(typeof secret!=='undefined'){payload['secret']=secret;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};this.users={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/users';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};this.users={list:(search,limit,offset,after,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/users';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
|
||||
if(typeof limit!=='undefined'){payload['limit']=limit;}
|
||||
if(typeof offset!=='undefined'){payload['offset']=offset;}
|
||||
if(typeof after!=='undefined'){payload['after']=after;}
|
||||
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(userId,email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
|
||||
|
@ -475,8 +487,17 @@ if(typeof password!=='undefined'){payload['password']=password;}
|
|||
if(typeof name!=='undefined'){payload['name']=name;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),delete:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getLogs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}/logs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getPrefs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateEmail:(userId,email)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
|
||||
let path='/users/{userId}/email'.replace('{userId}',userId);let payload={};if(typeof email!=='undefined'){payload['email']=email;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getLogs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}/logs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateName:(userId,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
|
||||
let path='/users/{userId}/name'.replace('{userId}',userId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updatePassword:(userId,password)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
|
||||
let path='/users/{userId}/password'.replace('{userId}',userId);let payload={};if(typeof password!=='undefined'){payload['password']=password;}
|
||||
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getPrefs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePrefs:(userId,prefs)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
|
||||
if(typeof prefs==='undefined'){throw new AppwriteException('Missing required parameter: "prefs"');}
|
||||
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};if(typeof prefs!=='undefined'){payload['prefs']=prefs;}
|
||||
|
|
8
public/dist/scripts/app.js
vendored
8
public/dist/scripts/app.js
vendored
|
@ -111,7 +111,7 @@ result+'")": '+
|
|||
error);}
|
||||
if(debug){console.info("debug-ls-if result:",result);}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility="hidden";element.style.display="none";}else{element.style.removeProperty("display");element.style.removeProperty("visibility");}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}},});window.ls.container.get("view").add({selector:"data-ls-loop",template:false,nested:false,controller:function(element,view,container,filter,window,expression){let expr=expression.parse(element.getAttribute("data-ls-loop"));let as=element.getAttribute("data-ls-as");let filterName=element.getAttribute("data-ls-filter");let key=element.getAttribute("data-ls-key")||"$index";let prefix=element.getAttribute("data-ls-prefix")||null;let postfix=element.getAttribute("data-ls-postfix")||null;let limit=parseInt(expression.parse(element.getAttribute("data-ls-limit")||"")||-1);let debug=element.getAttribute("data-debug")||false;let echo=function(){let array=container.path(expr);let counter=0;array=!array?[]:array;if(filterName){array=filter.apply(filterName,array);console.log(array);}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}},});window.ls.container.get("view").add({selector:"data-ls-loop",template:false,nested:false,controller:function(element,view,container,filter,window,expression){let expr=expression.parse(element.getAttribute("data-ls-loop"));let as=element.getAttribute("data-ls-as");let filterName=element.getAttribute("data-ls-filter");let key=element.getAttribute("data-ls-key")||"$index";let prefix=element.getAttribute("data-ls-prefix")||null;let postfix=element.getAttribute("data-ls-postfix")||null;let limit=parseInt(expression.parse(element.getAttribute("data-ls-limit")||"")||-1);let debug=element.getAttribute("data-debug")||false;let echo=function(){let array=container.path(expr);let counter=0;array=!array?[]:array;if(filterName){array=filter.apply(filterName,array);}
|
||||
let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
if(array instanceof Array&&typeof array!=="object"){throw new Error("Reference value must be array or object. "+typeof array+" given");}
|
||||
let children=[];element.$lsSkip=true;element.style.visibility=0===array.length&&element.style.visibility==""?"hidden":"visible";if(prefix){prefixElement=document.getElementById(prefix);let html=prefixElement.innerHTML;prefixElement=template.cloneNode(true);if(prefixElement){prefixElement.innerHTML=html;element.appendChild(prefixElement);view.render(prefixElement);}}
|
||||
|
@ -296,7 +296,7 @@ return'';}).add("runtimeLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUN
|
|||
return'';}).add("runtimeVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;}
|
||||
return'';}).add("indexAttributes",function($value){let output='';for(let i=0;i<$value.attributes.length;i++){output+=$value.attributes[i]+' ('+$value.orders[i]+'), '}
|
||||
return output.slice(0,-2);}).add("collectionAttributes",function($value){if(!Array.isArray($value)){return[];}
|
||||
$value.unshift({$id:'$id'});return $value;}).add("documentAttribute",function($value,attribute){if($value[attribute.$id]){return $value[attribute.$id];}
|
||||
$value.unshift({$id:'$id'});return $value;}).add("documentAttribute",function($value,attribute){if($value[attribute.key]){return $value[attribute.key];}
|
||||
return null;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);}
|
||||
let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";}
|
||||
return annotate(number,maxPlaces,forcePlaces,abbr);}
|
||||
|
@ -374,8 +374,8 @@ element.setAttribute("data-id-type",idType);info.innerHTML="Appwrite will genera
|
|||
button.className=idType=="custom"?"icon-shuffle copy":"icon-edit copy";}
|
||||
const syncEditorWithID=function(event){if(element.value!=='unique()'||idType!='auto'){writer.value=element.value;}
|
||||
if(idType=='auto'){element.value='unique()';}}
|
||||
const keypress=function(e){const key=e.which||e.keyCode;const ZERO=48;const NINE=57;const SMALL_A=97;const SMALL_Z=122;const CAPITAL_A=65;const CAPITAL_Z=90;const UNDERSCORE=95;const isNotValidDigit=key<ZERO||key>NINE;const isNotValidSmallAlphabet=key<SMALL_A||key>SMALL_Z;const isNotValidCapitalAlphabet=key<CAPITAL_A||key>CAPITAL_Z;if(key==UNDERSCORE&&e.target.value.length==0){e.preventDefault();}
|
||||
if(key!=UNDERSCORE&&isNotValidDigit&&isNotValidSmallAlphabet&&isNotValidCapitalAlphabet){e.preventDefault();}}
|
||||
const keypress=function(e){const key=e.which||e.keyCode;const ZERO=48;const NINE=57;const SMALL_A=97;const SMALL_Z=122;const CAPITAL_A=65;const CAPITAL_Z=90;const UNDERSCORE=95;const HYPHEN=45;const PERIOD=46;const isNotValidDigit=key<ZERO||key>NINE;const isNotValidSmallAlphabet=key<SMALL_A||key>SMALL_Z;const isNotValidCapitalAlphabet=key<CAPITAL_A||key>CAPITAL_Z;const isNotValidFirstChar=(key===UNDERSCORE||key===HYPHEN||key===PERIOD);if(isNotValidFirstChar&&e.target.value.length==0){e.preventDefault();}
|
||||
if(key!=UNDERSCORE&&key!=HYPHEN&&key!=PERIOD&&isNotValidDigit&&isNotValidSmallAlphabet&&isNotValidCapitalAlphabet){e.preventDefault();}}
|
||||
syncEditorWithID();setIdType(idType);writer.addEventListener("change",function(event){element.value=writer.value;});writer.form.addEventListener('reset',function(event){const resetEvent=new Event('reset');element.dispatchEvent(resetEvent);});element.addEventListener('reset',function(event){idType=element.getAttribute('data-id-type');setIdType(idType);});writer.addEventListener('keypress',keypress);button.addEventListener("click",switchType);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-document",controller:function(element,container,search){var formsDocument=(element.dataset["formsDocument"]||'');var searchButton=(element.dataset["search"]||0);let path=container.scope(searchButton);element.addEventListener('click',function(){search.selected=element.value;search.path=path;document.dispatchEvent(new CustomEvent(formsDocument,{bubbles:false,cancelable:true}));});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-duplications",controller:function(element){let validate=function(element){let duplication=0;let form=element.form;for(let i=0;i<form.elements.length;i++){let field=form.elements[i];if(field.name===element.name&&field.value===element.value){duplication++;}}
|
||||
if(duplication>1){element.setCustomValidity("Duplicated value");}
|
||||
else{element.setCustomValidity("");}};element.addEventListener('change',function(event){validate(event.target)});element.addEventListener('focus',function(event){validate(event.target)});element.addEventListener('blur',function(event){validate(event.target)});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-document-preview",controller:function(element,container,search){element.addEventListener('change',function(){console.log(element.value);});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-filter",controller:function(document,container,expression,element,form,di){let name=element.dataset["formsFilter"]||"";let events=element.dataset["event"]||"";let serialize=function(obj,prefix){let str=[],p;for(p in obj){if(obj.hasOwnProperty(p)){let k=prefix?prefix+"["+p+"]":p,v=obj[p];if(v===""){continue;}
|
||||
|
|
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
|
@ -906,11 +906,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
listCollections: (search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
listCollections: (search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/database/collections';
|
||||
let payload = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
|
@ -922,6 +923,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -937,18 +941,22 @@
|
|||
*
|
||||
* @param {string} collectionId
|
||||
* @param {string} name
|
||||
* @param {string} permission
|
||||
* @param {string} read
|
||||
* @param {string} write
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createCollection: (collectionId, name, read, write) => __awaiter(this, void 0, void 0, function* () {
|
||||
createCollection: (collectionId, name, permission, read, write) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof collectionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "collectionId"');
|
||||
}
|
||||
if (typeof name === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "name"');
|
||||
}
|
||||
if (typeof permission === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "permission"');
|
||||
}
|
||||
if (typeof read === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "read"');
|
||||
}
|
||||
|
@ -963,6 +971,9 @@
|
|||
if (typeof name !== 'undefined') {
|
||||
payload['name'] = name;
|
||||
}
|
||||
if (typeof permission !== 'undefined') {
|
||||
payload['permission'] = permission;
|
||||
}
|
||||
if (typeof read !== 'undefined') {
|
||||
payload['read'] = read;
|
||||
}
|
||||
|
@ -1002,23 +1013,30 @@
|
|||
*
|
||||
* @param {string} collectionId
|
||||
* @param {string} name
|
||||
* @param {string} permission
|
||||
* @param {string} read
|
||||
* @param {string} write
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
updateCollection: (collectionId, name, read, write) => __awaiter(this, void 0, void 0, function* () {
|
||||
updateCollection: (collectionId, name, permission, read, write) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof collectionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "collectionId"');
|
||||
}
|
||||
if (typeof name === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "name"');
|
||||
}
|
||||
if (typeof permission === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "permission"');
|
||||
}
|
||||
let path = '/database/collections/{collectionId}'.replace('{collectionId}', collectionId);
|
||||
let payload = {};
|
||||
if (typeof name !== 'undefined') {
|
||||
payload['name'] = name;
|
||||
}
|
||||
if (typeof permission !== 'undefined') {
|
||||
payload['permission'] = permission;
|
||||
}
|
||||
if (typeof read !== 'undefined') {
|
||||
payload['read'] = read;
|
||||
}
|
||||
|
@ -1345,23 +1363,19 @@
|
|||
*
|
||||
* @param {string} collectionId
|
||||
* @param {string} attributeId
|
||||
* @param {number} size
|
||||
* @param {boolean} required
|
||||
* @param {string} xdefault
|
||||
* @param {boolean} array
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createUrlAttribute: (collectionId, attributeId, size, required, xdefault, array) => __awaiter(this, void 0, void 0, function* () {
|
||||
createUrlAttribute: (collectionId, attributeId, required, xdefault, array) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof collectionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "collectionId"');
|
||||
}
|
||||
if (typeof attributeId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "attributeId"');
|
||||
}
|
||||
if (typeof size === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "size"');
|
||||
}
|
||||
if (typeof required === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "required"');
|
||||
}
|
||||
|
@ -1370,9 +1384,6 @@
|
|||
if (typeof attributeId !== 'undefined') {
|
||||
payload['attributeId'] = attributeId;
|
||||
}
|
||||
if (typeof size !== 'undefined') {
|
||||
payload['size'] = size;
|
||||
}
|
||||
if (typeof required !== 'undefined') {
|
||||
payload['required'] = required;
|
||||
}
|
||||
|
@ -1445,12 +1456,13 @@
|
|||
* @param {string[]} queries
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string[]} orderAttributes
|
||||
* @param {string[]} orderTypes
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
listDocuments: (collectionId, queries, limit, offset, orderAttributes, orderTypes) => __awaiter(this, void 0, void 0, function* () {
|
||||
listDocuments: (collectionId, queries, limit, offset, after, orderAttributes, orderTypes) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof collectionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "collectionId"');
|
||||
}
|
||||
|
@ -1465,6 +1477,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderAttributes !== 'undefined') {
|
||||
payload['orderAttributes'] = orderAttributes;
|
||||
}
|
||||
|
@ -1670,8 +1685,6 @@
|
|||
if (typeof orders !== 'undefined') {
|
||||
payload['orders'] = orders;
|
||||
}
|
||||
|
||||
console.log(collectionId, indexId, type, attributes, orders);
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('post', uri, {
|
||||
'content-type': 'application/json',
|
||||
|
@ -1724,7 +1737,7 @@
|
|||
}, payload);
|
||||
}),
|
||||
/**
|
||||
* Get Collection Logs
|
||||
* List Collection Logs
|
||||
*
|
||||
* Get the collection activity logs list by its unique ID.
|
||||
*
|
||||
|
@ -1754,11 +1767,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
list: (search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
list: (search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/functions';
|
||||
let payload = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
|
@ -1770,6 +1784,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -1941,10 +1958,11 @@
|
|||
* @param {string} functionId
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
listExecutions: (functionId, limit, offset) => __awaiter(this, void 0, void 0, function* () {
|
||||
listExecutions: (functionId, limit, offset, after) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof functionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "functionId"');
|
||||
}
|
||||
|
@ -1956,6 +1974,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('get', uri, {
|
||||
'content-type': 'application/json',
|
||||
|
@ -2051,11 +2072,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
listTags: (functionId, search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
listTags: (functionId, search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof functionId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "functionId"');
|
||||
}
|
||||
|
@ -2070,6 +2092,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -2516,11 +2541,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
list: (search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
list: (search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/projects';
|
||||
let payload = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
|
@ -2532,6 +2558,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -3457,11 +3486,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
listFiles: (search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
listFiles: (search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/storage/files';
|
||||
let payload = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
|
@ -3473,6 +3503,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -3728,11 +3761,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
list: (search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
list: (search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/teams';
|
||||
let payload = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
|
@ -3744,6 +3778,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -3869,11 +3906,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getMemberships: (teamId, search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
getMemberships: (teamId, search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof teamId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "teamId"');
|
||||
}
|
||||
|
@ -3888,6 +3926,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -4088,11 +4129,12 @@
|
|||
* @param {string} search
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @param {string} after
|
||||
* @param {string} orderType
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
list: (search, limit, offset, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
list: (search, limit, offset, after, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/users';
|
||||
let payload = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
|
@ -4104,6 +4146,9 @@
|
|||
if (typeof offset !== 'undefined') {
|
||||
payload['offset'] = offset;
|
||||
}
|
||||
if (typeof after !== 'undefined') {
|
||||
payload['after'] = after;
|
||||
}
|
||||
if (typeof orderType !== 'undefined') {
|
||||
payload['orderType'] = orderType;
|
||||
}
|
||||
|
@ -4193,6 +4238,33 @@
|
|||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}),
|
||||
/**
|
||||
* Update Email
|
||||
*
|
||||
* Update the user email by its unique ID.
|
||||
*
|
||||
* @param {string} userId
|
||||
* @param {string} email
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
updateEmail: (userId, email) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof userId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "userId"');
|
||||
}
|
||||
if (typeof email === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "email"');
|
||||
}
|
||||
let path = '/users/{userId}/email'.replace('{userId}', userId);
|
||||
let payload = {};
|
||||
if (typeof email !== 'undefined') {
|
||||
payload['email'] = email;
|
||||
}
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('patch', uri, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}),
|
||||
/**
|
||||
* Get User Logs
|
||||
*
|
||||
|
@ -4213,6 +4285,60 @@
|
|||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}),
|
||||
/**
|
||||
* Update Name
|
||||
*
|
||||
* Update the user name by its unique ID.
|
||||
*
|
||||
* @param {string} userId
|
||||
* @param {string} name
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
updateName: (userId, name) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof userId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "userId"');
|
||||
}
|
||||
if (typeof name === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "name"');
|
||||
}
|
||||
let path = '/users/{userId}/name'.replace('{userId}', userId);
|
||||
let payload = {};
|
||||
if (typeof name !== 'undefined') {
|
||||
payload['name'] = name;
|
||||
}
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('patch', uri, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}),
|
||||
/**
|
||||
* Update Password
|
||||
*
|
||||
* Update the user password by its unique ID.
|
||||
*
|
||||
* @param {string} userId
|
||||
* @param {string} password
|
||||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
updatePassword: (userId, password) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (typeof userId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "userId"');
|
||||
}
|
||||
if (typeof password === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "password"');
|
||||
}
|
||||
let path = '/users/{userId}/password'.replace('{userId}', userId);
|
||||
let payload = {};
|
||||
if (typeof password !== 'undefined') {
|
||||
payload['password'] = password;
|
||||
}
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('patch', uri, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}),
|
||||
/**
|
||||
* Get User Preferences
|
||||
*
|
||||
|
@ -4544,4 +4670,4 @@
|
|||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
}(this.window = this.window || {}, null, window));
|
||||
}(this.window = this.window || {}, null, window));
|
||||
|
|
|
@ -275,8 +275,8 @@ window.ls.filter
|
|||
return $value;
|
||||
})
|
||||
.add("documentAttribute", function($value, attribute) {
|
||||
if($value[attribute.$id]) {
|
||||
return $value[attribute.$id];
|
||||
if($value[attribute.key]) {
|
||||
return $value[attribute.key];
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -114,16 +114,19 @@
|
|||
const CAPITAL_A = 65;
|
||||
const CAPITAL_Z = 90;
|
||||
const UNDERSCORE = 95;
|
||||
const HYPHEN = 45;
|
||||
const PERIOD = 46;
|
||||
|
||||
const isNotValidDigit = key < ZERO || key > NINE;
|
||||
const isNotValidSmallAlphabet = key < SMALL_A || key > SMALL_Z;
|
||||
const isNotValidCapitalAlphabet = key < CAPITAL_A || key > CAPITAL_Z;
|
||||
|
||||
const isNotValidFirstChar = (key === UNDERSCORE || key === HYPHEN || key === PERIOD);
|
||||
//Leading underscore is prevented
|
||||
if (key == UNDERSCORE && e.target.value.length == 0) {
|
||||
if ( isNotValidFirstChar && e.target.value.length == 0) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (key != UNDERSCORE && isNotValidDigit && isNotValidSmallAlphabet && isNotValidCapitalAlphabet) {
|
||||
if (key != UNDERSCORE && key != HYPHEN && key != PERIOD && isNotValidDigit && isNotValidSmallAlphabet && isNotValidCapitalAlphabet) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,17 @@
|
|||
z-index: 1;
|
||||
opacity: 1!important;
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
// content: "";
|
||||
// position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
background: var(--config-color-background-focus);
|
||||
// background: var(--config-color-background-focus);
|
||||
}
|
||||
|
||||
&.inline {
|
||||
|
|
|
@ -783,6 +783,12 @@
|
|||
"css": "key",
|
||||
"code": 59479,
|
||||
"src": "elusive"
|
||||
},
|
||||
{
|
||||
"uid": "3256ef03b16e7ab51235bc7378b53bb5",
|
||||
"css": "boolean",
|
||||
"code": 61957,
|
||||
"src": "fontawesome"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1209,6 +1209,12 @@ ol {
|
|||
.pull-start;
|
||||
}
|
||||
|
||||
i.avatar {
|
||||
text-align: center;
|
||||
background: var(--config-color-dark);
|
||||
color: var(--config-color-background-fade);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -835,11 +835,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
.scroll-to {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@media @desktops {
|
||||
.logo {
|
||||
.top {
|
||||
|
|
|
@ -42,6 +42,7 @@ abstract class Migration
|
|||
'0.9.1' => 'V08',
|
||||
'0.9.2' => 'V08',
|
||||
'0.9.3' => 'V08',
|
||||
'0.9.4' => 'V08',
|
||||
'0.10.0' => 'V08', // TODO Eldad: `I need this to pass the tests`
|
||||
];
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace Appwrite\Specification\Format;
|
|||
|
||||
use Appwrite\Specification\Format;
|
||||
use Appwrite\Template\Template;
|
||||
use stdClass;
|
||||
use Utopia\Validator;
|
||||
|
||||
class OpenAPI3 extends Format
|
||||
|
@ -21,6 +20,34 @@ class OpenAPI3 extends Format
|
|||
return 'Open API 3';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Used Models
|
||||
*
|
||||
* Recursively get all used models
|
||||
*
|
||||
* @param object $model
|
||||
* @param array $models
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function getUsedModels($model, array &$usedModels)
|
||||
{
|
||||
if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) {
|
||||
$usedModels[] = $model;
|
||||
return;
|
||||
}
|
||||
if (!is_object($model)) return;
|
||||
foreach ($model->getRules() as $rule) {
|
||||
if(\is_array($rule['type'])) {
|
||||
foreach ($rule['type'] as $type) {
|
||||
$this->getUsedModels($type, $usedModels);
|
||||
}
|
||||
} else {
|
||||
$this->getUsedModels($rule['type'], $usedModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
|
@ -71,7 +98,7 @@ class OpenAPI3 extends Format
|
|||
if (isset($output['components']['securitySchemes']['Project'])) {
|
||||
$output['components']['securitySchemes']['Project']['x-appwrite'] = ['demo' => '5df5acd0d48c2'];
|
||||
}
|
||||
|
||||
|
||||
if (isset($output['components']['securitySchemes']['Key'])) {
|
||||
$output['components']['securitySchemes']['Key']['x-appwrite'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2'];
|
||||
}
|
||||
|
@ -79,7 +106,7 @@ class OpenAPI3 extends Format
|
|||
if (isset($output['securityDefinitions']['JWT'])) {
|
||||
$output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...'];
|
||||
}
|
||||
|
||||
|
||||
if (isset($output['components']['securitySchemes']['Locale'])) {
|
||||
$output['components']['securitySchemes']['Locale']['x-appwrite'] = ['demo' => 'en'];
|
||||
}
|
||||
|
@ -91,7 +118,7 @@ class OpenAPI3 extends Format
|
|||
$usedModels = [];
|
||||
|
||||
foreach ($this->routes as $route) { /** @var \Utopia\Route $route */
|
||||
$url = \str_replace('/v1', '', $route->getURL());
|
||||
$url = \str_replace('/v1', '', $route->getPath());
|
||||
$scope = $route->getLabel('scope', '');
|
||||
$hide = $route->getLabel('sdk.hide', false);
|
||||
$consumes = [$route->getLabel('sdk.request.type', 'application/json')];
|
||||
|
@ -103,7 +130,7 @@ class OpenAPI3 extends Format
|
|||
$id = $route->getLabel('sdk.method', \uniqid());
|
||||
$desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null;
|
||||
$produces = $route->getLabel('sdk.response.type', null);
|
||||
$model = $route->getLabel('sdk.response.model', 'none');
|
||||
$model = $route->getLabel('sdk.response.model', 'none');
|
||||
$routeSecurity = $route->getLabel('sdk.auth', []);
|
||||
$sdkPlatofrms = [];
|
||||
|
||||
|
@ -127,7 +154,7 @@ class OpenAPI3 extends Format
|
|||
if(empty($routeSecurity)) {
|
||||
$sdkPlatofrms[] = APP_PLATFORM_CLIENT;
|
||||
}
|
||||
|
||||
|
||||
$temp = [
|
||||
'summary' => $route->getDesc(),
|
||||
'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id),
|
||||
|
@ -153,13 +180,24 @@ class OpenAPI3 extends Format
|
|||
];
|
||||
|
||||
foreach ($this->models as $key => $value) {
|
||||
if($value->getType() === $model) {
|
||||
$model = $value;
|
||||
break;
|
||||
if(\is_array($model)) {
|
||||
$model = \array_map(function($m) use($value) {
|
||||
if($m === $value->getType()) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $m;
|
||||
}, $model);
|
||||
} else {
|
||||
if($value->getType() === $model) {
|
||||
$model = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($model->isNone()) {
|
||||
if(!(\is_array($model)) && $model->isNone()) {
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => (in_array($produces, [
|
||||
'image/*',
|
||||
|
@ -176,17 +214,43 @@ class OpenAPI3 extends Format
|
|||
// ],
|
||||
];
|
||||
} else {
|
||||
$usedModels[] = $model->getType();
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => $model->getName(),
|
||||
'content' => [
|
||||
$produces => [
|
||||
'schema' => [
|
||||
'$ref' => '#/components/schemas/'.$model->getType(),
|
||||
if(\is_array($model)) {
|
||||
$modelDescription = \join(', or ', \array_map(function ($m) {
|
||||
return $m->getName();
|
||||
}, $model));
|
||||
|
||||
// model has multiple possible responses, we will use oneOf
|
||||
foreach ($model as $m) {
|
||||
$usedModels[] = $m->getType();
|
||||
}
|
||||
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => $modelDescription,
|
||||
'content' => [
|
||||
$produces => [
|
||||
'schema' => [
|
||||
'oneOf' => \array_map(function($m) {
|
||||
return ['$ref' => '#/components/schemas/'.$m->getType()];
|
||||
}, $model)
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
];
|
||||
} else {
|
||||
// Response definition using one type
|
||||
$usedModels[] = $model->getType();
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => $model->getName(),
|
||||
'content' => [
|
||||
$produces => [
|
||||
'schema' => [
|
||||
'$ref' => '#/components/schemas/'.$model->getType(),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($route->getLabel('sdk.response.code', 500) === 204) {
|
||||
|
@ -196,7 +260,7 @@ class OpenAPI3 extends Format
|
|||
|
||||
if ((!empty($scope))) { // && 'public' != $scope
|
||||
$securities = ['Project' => []];
|
||||
|
||||
|
||||
foreach($route->getLabel('sdk.auth', []) as $security) {
|
||||
if(array_key_exists($security, $this->keys)) {
|
||||
$securities[$security] = [];
|
||||
|
@ -352,11 +416,7 @@ class OpenAPI3 extends Format
|
|||
$output['paths'][$url][\strtolower($route->getMethod())] = $temp;
|
||||
}
|
||||
foreach ($this->models as $model) {
|
||||
foreach ($model->getRules() as $rule) {
|
||||
if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) {
|
||||
$usedModels[] = $rule['type'];
|
||||
}
|
||||
}
|
||||
$this->getUsedModels($model, $usedModels);
|
||||
}
|
||||
foreach ($this->models as $model) {
|
||||
if (!in_array($model->getType(), $usedModels) && $model->getType() !== 'error') {
|
||||
|
@ -378,7 +438,7 @@ class OpenAPI3 extends Format
|
|||
if($model->isAny()) {
|
||||
$output['components']['schemas'][$model->getType()]['additionalProperties'] = true;
|
||||
}
|
||||
|
||||
|
||||
if(!empty($required)) {
|
||||
$output['components']['schemas'][$model->getType()]['required'] = $required;
|
||||
}
|
||||
|
@ -393,7 +453,7 @@ class OpenAPI3 extends Format
|
|||
case 'json':
|
||||
$type = 'string';
|
||||
break;
|
||||
|
||||
|
||||
case 'integer':
|
||||
$type = 'integer';
|
||||
$format = 'int32';
|
||||
|
@ -403,18 +463,39 @@ class OpenAPI3 extends Format
|
|||
$type = 'number';
|
||||
$format = 'float';
|
||||
break;
|
||||
|
||||
|
||||
case 'double':
|
||||
$type = 'number';
|
||||
$format = 'double';
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
$type = 'boolean';
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
$type = 'object';
|
||||
$rule['type'] = ($rule['type']) ? $rule['type'] : 'none';
|
||||
|
||||
$items = [
|
||||
'$ref' => '#/components/schemas/'.$rule['type'],
|
||||
];
|
||||
if(\is_array($rule['type'])) {
|
||||
if($rule['array']) {
|
||||
$items = [
|
||||
'anyOf' => \array_map(function($type) {
|
||||
return ['$ref' => '#/components/schemas/'.$type];
|
||||
}, $rule['type'])
|
||||
];
|
||||
} else {
|
||||
$items = [
|
||||
'oneOf' => \array_map(function($type) {
|
||||
return ['$ref' => '#/components/schemas/'.$type];
|
||||
}, $rule['type'])
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$items = [
|
||||
'$ref' => '#/components/schemas/'.$rule['type'],
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,34 @@ class Swagger2 extends Format
|
|||
return 'Swagger 2';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Used Models
|
||||
*
|
||||
* Recursively get all used models
|
||||
*
|
||||
* @param object $model
|
||||
* @param array $models
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function getUsedModels($model, array &$usedModels)
|
||||
{
|
||||
if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) {
|
||||
$usedModels[] = $model;
|
||||
return;
|
||||
}
|
||||
if (!is_object($model)) return;
|
||||
foreach ($model->getRules() as $rule) {
|
||||
if(\is_array($rule['type'])) {
|
||||
foreach ($rule['type'] as $type) {
|
||||
$this->getUsedModels($type, $usedModels);
|
||||
}
|
||||
} else {
|
||||
$this->getUsedModels($rule['type'], $usedModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
|
@ -69,15 +97,15 @@ class Swagger2 extends Format
|
|||
if (isset($output['securityDefinitions']['Project'])) {
|
||||
$output['securityDefinitions']['Project']['x-appwrite'] = ['demo' => '5df5acd0d48c2'];
|
||||
}
|
||||
|
||||
|
||||
if (isset($output['securityDefinitions']['Key'])) {
|
||||
$output['securityDefinitions']['Key']['x-appwrite'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2'];
|
||||
}
|
||||
|
||||
|
||||
if (isset($output['securityDefinitions']['JWT'])) {
|
||||
$output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...'];
|
||||
}
|
||||
|
||||
|
||||
if (isset($output['securityDefinitions']['Locale'])) {
|
||||
$output['securityDefinitions']['Locale']['x-appwrite'] = ['demo' => 'en'];
|
||||
}
|
||||
|
@ -89,7 +117,7 @@ class Swagger2 extends Format
|
|||
$usedModels = [];
|
||||
|
||||
foreach ($this->routes as $route) { /** @var \Utopia\Route $route */
|
||||
$url = \str_replace('/v1', '', $route->getURL());
|
||||
$url = \str_replace('/v1', '', $route->getPath());
|
||||
$scope = $route->getLabel('scope', '');
|
||||
$hide = $route->getLabel('sdk.hide', false);
|
||||
$consumes = [$route->getLabel('sdk.request.type', 'application/json')];
|
||||
|
@ -125,7 +153,7 @@ class Swagger2 extends Format
|
|||
if(empty($routeSecurity)) {
|
||||
$sdkPlatofrms[] = APP_PLATFORM_CLIENT;
|
||||
}
|
||||
|
||||
|
||||
$temp = [
|
||||
'summary' => $route->getDesc(),
|
||||
'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id),
|
||||
|
@ -155,13 +183,22 @@ class Swagger2 extends Format
|
|||
}
|
||||
|
||||
foreach ($this->models as $key => $value) {
|
||||
if($value->getType() === $model) {
|
||||
$model = $value;
|
||||
break;
|
||||
if(\is_array($model)) {
|
||||
$model = \array_map(function($m) use($value) {
|
||||
if($m === $value->getType()) {
|
||||
return $value;
|
||||
}
|
||||
return $m;
|
||||
}, $model);
|
||||
} else {
|
||||
if($value->getType() === $model) {
|
||||
$model = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($model->isNone()) {
|
||||
if(!(\is_array($model)) && $model->isNone()) {
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => (in_array($produces, [
|
||||
'image/*',
|
||||
|
@ -178,13 +215,41 @@ class Swagger2 extends Format
|
|||
],
|
||||
];
|
||||
} else {
|
||||
$usedModels[] = $model->getType();
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => $model->getName(),
|
||||
'schema' => [
|
||||
'$ref' => '#/definitions/'.$model->getType(),
|
||||
],
|
||||
];
|
||||
|
||||
if(\is_array($model)) {
|
||||
$modelDescription = \join(', or ', \array_map(function ($m) {
|
||||
return $m->getName();
|
||||
}, $model));
|
||||
// model has multiple possible responses, we will use oneOf
|
||||
foreach ($model as $m) {
|
||||
$usedModels[] = $m->getType();
|
||||
}
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => $modelDescription,
|
||||
'content' => [
|
||||
$produces => [
|
||||
'schema' => [
|
||||
'oneOf' => \array_map(function($m) {
|
||||
return ['$ref' => '#/definitions/'.$m->getType()];
|
||||
}, $model)
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
} else {
|
||||
// Response definition using one type
|
||||
$usedModels[] = $model->getType();
|
||||
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
|
||||
'description' => $model->getName(),
|
||||
'content' => [
|
||||
$produces => [
|
||||
'schema' => [
|
||||
'$ref' => '#/definitions/'.$model->getType(),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if(in_array($route->getLabel('sdk.response.code', 500), [204, 301, 302, 308], true)) {
|
||||
|
@ -194,7 +259,7 @@ class Swagger2 extends Format
|
|||
|
||||
if ((!empty($scope))) { // && 'public' != $scope
|
||||
$securities = ['Project' => []];
|
||||
|
||||
|
||||
foreach($route->getLabel('sdk.auth', []) as $security) {
|
||||
if(array_key_exists($security, $this->keys)) {
|
||||
$securities[$security] = [];
|
||||
|
@ -204,7 +269,7 @@ class Swagger2 extends Format
|
|||
$temp['x-appwrite']['auth'] = array_slice($securities, 0, $this->authCount);
|
||||
$temp['security'][] = $securities;
|
||||
}
|
||||
|
||||
|
||||
$body = [
|
||||
'name' => 'payload',
|
||||
'in' => 'body',
|
||||
|
@ -354,15 +419,9 @@ class Swagger2 extends Format
|
|||
$output['paths'][$url][\strtolower($route->getMethod())] = $temp;
|
||||
}
|
||||
foreach ($this->models as $model) {
|
||||
foreach ($model->getRules() as $rule) {
|
||||
if (
|
||||
in_array($model->getType(), $usedModels)
|
||||
&& !in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])
|
||||
) {
|
||||
$usedModels[] = $rule['type'];
|
||||
}
|
||||
}
|
||||
$this->getUsedModels($model, $usedModels);
|
||||
}
|
||||
|
||||
foreach ($this->models as $model) {
|
||||
if (!in_array($model->getType(), $usedModels)) {
|
||||
continue;
|
||||
|
@ -383,7 +442,7 @@ class Swagger2 extends Format
|
|||
if($model->isAny()) {
|
||||
$output['definitions'][$model->getType()]['additionalProperties'] = true;
|
||||
}
|
||||
|
||||
|
||||
if(!empty($required)) {
|
||||
$output['definitions'][$model->getType()]['required'] = $required;
|
||||
}
|
||||
|
@ -398,7 +457,7 @@ class Swagger2 extends Format
|
|||
case 'json':
|
||||
$type = 'string';
|
||||
break;
|
||||
|
||||
|
||||
case 'integer':
|
||||
$type = 'integer';
|
||||
$format = 'int32';
|
||||
|
@ -408,19 +467,40 @@ class Swagger2 extends Format
|
|||
$type = 'number';
|
||||
$format = 'float';
|
||||
break;
|
||||
|
||||
|
||||
case 'double':
|
||||
$type = 'number';
|
||||
$format = 'double';
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
$type = 'boolean';
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
$type = 'object';
|
||||
$rule['type'] = ($rule['type']) ? $rule['type'] : 'none';
|
||||
|
||||
$items = [
|
||||
'type' => $type,
|
||||
'$ref' => '#/definitions/'.$rule['type'],
|
||||
];
|
||||
if(\is_array($rule['type'])) {
|
||||
if($rule['array']) {
|
||||
$items = [
|
||||
'anyOf' => \array_map(function($type) {
|
||||
return ['$ref' => '#/definitions/'.$type];
|
||||
}, $rule['type'])
|
||||
];
|
||||
} else {
|
||||
$items = [
|
||||
'oneOf' => \array_map(function($type) {
|
||||
return ['$ref' => '#/definitions/'.$type];
|
||||
}, $rule['type'])
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$items = [
|
||||
'type' => $type,
|
||||
'$ref' => '#/definitions/'.$rule['type'],
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ class Stats
|
|||
$functionExecutionTime = $this->params['functionExecutionTime'] ?? 0;
|
||||
$functionStatus = $this->params['functionStatus'] ?? '';
|
||||
|
||||
$tags = ",project={$projectId},version=" . App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$tags = ",projectId={$projectId},version=" . App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
// the global namespace is prepended to every key (optional)
|
||||
$this->statsd->setNamespace($this->namespace);
|
||||
|
@ -112,7 +112,70 @@ class Stats
|
|||
$this->statsd->count('network.outbound' . $tags, $networkResponseSize);
|
||||
$this->statsd->count('network.all' . $tags, $networkRequestSize + $networkResponseSize);
|
||||
|
||||
$dbMetrics = [
|
||||
'database.collections.create',
|
||||
'database.collections.read',
|
||||
'database.collections.update',
|
||||
'database.collections.delete',
|
||||
'database.documents.create',
|
||||
'database.documents.read',
|
||||
'database.documents.update',
|
||||
'database.documents.delete',
|
||||
];
|
||||
|
||||
foreach ($dbMetrics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
$tags = ",projectId={$projectId},collectionId=" . ($this->params['collectionId'] ?? '');
|
||||
$this->statsd->increment($metric . $tags);
|
||||
}
|
||||
}
|
||||
|
||||
$storageMertics = [
|
||||
'storage.files.create',
|
||||
'storage.files.read',
|
||||
'storage.files.update',
|
||||
'storage.files.delete',
|
||||
];
|
||||
|
||||
foreach ($storageMertics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
$tags = ",projectId={$projectId},bucketId=" . ($this->params['bucketId'] ?? '');
|
||||
$this->statsd->increment($metric . $tags);
|
||||
}
|
||||
}
|
||||
|
||||
$usersMetrics = [
|
||||
'users.create',
|
||||
'users.read',
|
||||
'users.update',
|
||||
'users.delete',
|
||||
];
|
||||
|
||||
foreach ($usersMetrics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
$tags = ",projectId={$projectId}";
|
||||
$this->statsd->increment($metric . $tags);
|
||||
}
|
||||
}
|
||||
|
||||
$sessionsMetrics = [
|
||||
'users.sessions.create',
|
||||
'users.sessions.delete',
|
||||
];
|
||||
|
||||
foreach ($sessionsMetrics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
$tags = ",projectId={$projectId},provider=". ($this->params['provider'] ?? '');
|
||||
$this->statsd->count($metric . $tags, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($storage >= 1) {
|
||||
$tags = ",projectId={$projectId},bucketId=" . ($this->params['bucketId'] ?? '');
|
||||
$this->statsd->count('storage.all' . $tags, $storage);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,14 @@ use Appwrite\Utopia\Response\Model;
|
|||
use Appwrite\Utopia\Response\Model\None;
|
||||
use Appwrite\Utopia\Response\Model\Any;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
use Appwrite\Utopia\Response\Model\AttributeList;
|
||||
use Appwrite\Utopia\Response\Model\AttributeString;
|
||||
use Appwrite\Utopia\Response\Model\AttributeInteger;
|
||||
use Appwrite\Utopia\Response\Model\AttributeFloat;
|
||||
use Appwrite\Utopia\Response\Model\AttributeBoolean;
|
||||
use Appwrite\Utopia\Response\Model\AttributeEmail;
|
||||
use Appwrite\Utopia\Response\Model\AttributeIP;
|
||||
use Appwrite\Utopia\Response\Model\AttributeURL;
|
||||
use Appwrite\Utopia\Response\Model\BaseList;
|
||||
use Appwrite\Utopia\Response\Model\Collection;
|
||||
use Appwrite\Utopia\Response\Model\Continent;
|
||||
|
@ -33,6 +41,7 @@ use Appwrite\Utopia\Response\Model\Team;
|
|||
use Appwrite\Utopia\Response\Model\Locale;
|
||||
use Appwrite\Utopia\Response\Model\Log;
|
||||
use Appwrite\Utopia\Response\Model\Membership;
|
||||
use Appwrite\Utopia\Response\Model\Metric;
|
||||
use Appwrite\Utopia\Response\Model\Permissions;
|
||||
use Appwrite\Utopia\Response\Model\Phone;
|
||||
use Appwrite\Utopia\Response\Model\Platform;
|
||||
|
@ -43,6 +52,13 @@ use Appwrite\Utopia\Response\Model\Token;
|
|||
use Appwrite\Utopia\Response\Model\Webhook;
|
||||
use Appwrite\Utopia\Response\Model\Preferences;
|
||||
use Appwrite\Utopia\Response\Model\Mock; // Keep last
|
||||
use Appwrite\Utopia\Response\Model\UsageBuckets;
|
||||
use Appwrite\Utopia\Response\Model\UsageCollection;
|
||||
use Appwrite\Utopia\Response\Model\UsageDatabase;
|
||||
use Appwrite\Utopia\Response\Model\UsageFunctions;
|
||||
use Appwrite\Utopia\Response\Model\UsageProject;
|
||||
use Appwrite\Utopia\Response\Model\UsageStorage;
|
||||
use Appwrite\Utopia\Response\Model\UsageUsers;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -56,19 +72,37 @@ class Response extends SwooleResponse
|
|||
const MODEL_LOG = 'log';
|
||||
const MODEL_LOG_LIST = 'logList';
|
||||
const MODEL_ERROR = 'error';
|
||||
const MODEL_METRIC = 'metric';
|
||||
const MODEL_METRIC_LIST = 'metricList';
|
||||
const MODEL_ERROR_DEV = 'errorDev';
|
||||
const MODEL_BASE_LIST = 'baseList';
|
||||
const MODEL_USAGE_DATABASE = 'usageDatabase';
|
||||
const MODEL_USAGE_COLLECTION = 'usageCollection';
|
||||
const MODEL_USAGE_USERS = 'usageUsers';
|
||||
const MODEL_USAGE_BUCKETS = 'usageBuckets';
|
||||
const MODEL_USAGE_STORAGE = 'usageStorage';
|
||||
const MODEL_USAGE_FUNCTIONS = 'usageFunctions';
|
||||
const MODEL_USAGE_PROJECT = 'usageProject';
|
||||
|
||||
// Database
|
||||
const MODEL_COLLECTION = 'collection';
|
||||
const MODEL_COLLECTION_LIST = 'collectionList';
|
||||
const MODEL_ATTRIBUTE = 'attribute';
|
||||
const MODEL_ATTRIBUTE_LIST = 'attributeList';
|
||||
const MODEL_INDEX = 'index';
|
||||
const MODEL_INDEX_LIST = 'indexList';
|
||||
const MODEL_DOCUMENT = 'document';
|
||||
const MODEL_DOCUMENT_LIST = 'documentList';
|
||||
|
||||
// Database Attributes
|
||||
const MODEL_ATTRIBUTE = 'attribute';
|
||||
const MODEL_ATTRIBUTE_LIST = 'attributeList';
|
||||
const MODEL_ATTRIBUTE_STRING = 'attributeString';
|
||||
const MODEL_ATTRIBUTE_INTEGER= 'attributeInteger';
|
||||
const MODEL_ATTRIBUTE_FLOAT= 'attributeFloat';
|
||||
const MODEL_ATTRIBUTE_BOOLEAN= 'attributeBoolean';
|
||||
const MODEL_ATTRIBUTE_EMAIL= 'attributeEmail';
|
||||
const MODEL_ATTRIBUTE_IP= 'attributeIp';
|
||||
const MODEL_ATTRIBUTE_URL= 'attributeUrl';
|
||||
|
||||
// Users
|
||||
const MODEL_USER = 'user';
|
||||
const MODEL_USER_LIST = 'userList';
|
||||
|
@ -125,6 +159,7 @@ class Response extends SwooleResponse
|
|||
// Deprecated
|
||||
const MODEL_PERMISSIONS = 'permissions';
|
||||
const MODEL_RULE = 'rule';
|
||||
const MODEL_TASK = 'task';
|
||||
|
||||
// Tests (keep last)
|
||||
const MODEL_MOCK = 'mock';
|
||||
|
@ -154,7 +189,6 @@ class Response extends SwooleResponse
|
|||
->setModel(new ErrorDev())
|
||||
// Lists
|
||||
->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION))
|
||||
->setModel(new BaseList('Attributes List', self::MODEL_ATTRIBUTE_LIST, 'attributes', self::MODEL_ATTRIBUTE))
|
||||
->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX))
|
||||
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
|
||||
->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER))
|
||||
|
@ -176,9 +210,18 @@ class Response extends SwooleResponse
|
|||
->setModel(new BaseList('Languages List', self::MODEL_LANGUAGE_LIST, 'languages', self::MODEL_LANGUAGE))
|
||||
->setModel(new BaseList('Currencies List', self::MODEL_CURRENCY_LIST, 'currencies', self::MODEL_CURRENCY))
|
||||
->setModel(new BaseList('Phones List', self::MODEL_PHONE_LIST, 'phones', self::MODEL_PHONE))
|
||||
->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false))
|
||||
// Entities
|
||||
->setModel(new Collection())
|
||||
->setModel(new Attribute())
|
||||
->setModel(new AttributeList())
|
||||
->setModel(new AttributeString())
|
||||
->setModel(new AttributeInteger())
|
||||
->setModel(new AttributeFloat())
|
||||
->setModel(new AttributeBoolean())
|
||||
->setModel(new AttributeEmail())
|
||||
->setModel(new AttributeIP())
|
||||
->setModel(new AttributeURL())
|
||||
->setModel(new Index())
|
||||
->setModel(new ModelDocument())
|
||||
->setModel(new Log())
|
||||
|
@ -204,6 +247,14 @@ class Response extends SwooleResponse
|
|||
->setModel(new Language())
|
||||
->setModel(new Currency())
|
||||
->setModel(new Phone())
|
||||
->setModel(new Metric())
|
||||
->setModel(new UsageDatabase())
|
||||
->setModel(new UsageCollection())
|
||||
->setModel(new UsageUsers())
|
||||
->setModel(new UsageStorage())
|
||||
->setModel(new UsageBuckets())
|
||||
->setModel(new UsageFunctions())
|
||||
->setModel(new UsageProject())
|
||||
// Verification
|
||||
// Recovery
|
||||
// Tests (keep last)
|
||||
|
@ -302,7 +353,7 @@ class Response extends SwooleResponse
|
|||
$document = $model->filter($document);
|
||||
|
||||
foreach ($model->getRules() as $key => $rule) {
|
||||
if (!$document->isSet($key)) {
|
||||
if (!$document->isSet($key) && $rule['require']) { // do not set attribute in response if not required
|
||||
if (!is_null($rule['default'])) {
|
||||
$document->setAttribute($key, $rule['default']);
|
||||
} else {
|
||||
|
@ -317,15 +368,33 @@ class Response extends SwooleResponse
|
|||
|
||||
foreach ($data[$key] as &$item) {
|
||||
if ($item instanceof Document) {
|
||||
if (!array_key_exists($rule['type'], $this->models)) {
|
||||
throw new Exception('Missing model for rule: '. $rule['type']);
|
||||
if (\is_array($rule['type'])) {
|
||||
foreach ($rule['type'] as $type) {
|
||||
$condition = false;
|
||||
foreach ($this->getModel($type)->conditions as $attribute => $val) {
|
||||
$condition = $item->getAttribute($attribute) === $val;
|
||||
if(!$condition) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($condition) {
|
||||
$ruleType = $type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$ruleType = $rule['type'];
|
||||
}
|
||||
|
||||
$item = $this->output($item, $rule['type']);
|
||||
if (!array_key_exists($ruleType, $this->models)) {
|
||||
throw new Exception('Missing model for rule: '. $ruleType);
|
||||
}
|
||||
|
||||
$item = $this->output($item, $ruleType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$output[$key] = $data[$key];
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ abstract class Model
|
|||
{
|
||||
const TYPE_STRING = 'string';
|
||||
const TYPE_INTEGER = 'integer';
|
||||
const TYPE_FLOAT = 'float';
|
||||
const TYPE_FLOAT = 'double';
|
||||
const TYPE_BOOLEAN = 'boolean';
|
||||
const TYPE_JSON = 'json';
|
||||
|
||||
|
@ -35,7 +35,7 @@ abstract class Model
|
|||
/**
|
||||
* Filter Document Structure
|
||||
*
|
||||
* @return string
|
||||
* @return Document
|
||||
*/
|
||||
public function filter(Document $document): Document
|
||||
{
|
||||
|
@ -68,6 +68,10 @@ abstract class Model
|
|||
|
||||
/**
|
||||
* Add a New Rule
|
||||
* If rule is an array of documents with varying models
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $options
|
||||
*/
|
||||
protected function addRule(string $key, array $options): self
|
||||
{
|
||||
|
@ -77,7 +81,7 @@ abstract class Model
|
|||
'description' => '',
|
||||
'default' => null,
|
||||
'example' => '',
|
||||
'array' => false,
|
||||
'array' => false
|
||||
], $options);
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -10,17 +10,11 @@ class Attribute extends Model
|
|||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$collection', [
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection ID.',
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16d55',
|
||||
])
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute ID.',
|
||||
'default' => '',
|
||||
'example' => '60ccf71b98a2d',
|
||||
'example' => 'fullName',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
|
@ -28,11 +22,11 @@ class Attribute extends Model
|
|||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('size', [
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute size.',
|
||||
'default' => 0,
|
||||
'example' => 128,
|
||||
'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`',
|
||||
'default' => '',
|
||||
'example' => 'available',
|
||||
])
|
||||
->addRule('required', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
|
@ -45,11 +39,13 @@ class Attribute extends Model
|
|||
'description' => 'Is attribute an array?',
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
'required' => false
|
||||
'require' => false
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
|
@ -69,4 +65,4 @@ class Attribute extends Model
|
|||
{
|
||||
return Response::MODEL_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
49
src/Appwrite/Utopia/Response/Model/AttributeBoolean.php
Normal file
49
src/Appwrite/Utopia/Response/Model/AttributeBoolean.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeBoolean extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => false,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_BOOLEAN
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeBoolean';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_BOOLEAN;
|
||||
}
|
||||
}
|
58
src/Appwrite/Utopia/Response/Model/AttributeEmail.php
Normal file
58
src/Appwrite/Utopia/Response/Model/AttributeEmail.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeEmail extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'String format.',
|
||||
'default' => APP_DATABASE_ATTRIBUTE_EMAIL,
|
||||
'example' => APP_DATABASE_ATTRIBUTE_EMAIL,
|
||||
'array' => false,
|
||||
'require' => true,
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => 'default@example.com',
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_STRING,
|
||||
'format' => \APP_DATABASE_ATTRIBUTE_EMAIL
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeEmail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_EMAIL;
|
||||
}
|
||||
}
|
65
src/Appwrite/Utopia/Response/Model/AttributeFloat.php
Normal file
65
src/Appwrite/Utopia/Response/Model/AttributeFloat.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeFloat extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('min', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Minimum value to enforce for new documents.',
|
||||
'default' => null,
|
||||
'example' => 1.5,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
->addRule('max', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Maximum value to enforce for new documents.',
|
||||
'default' => null,
|
||||
'example' => 10.5,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => 2.5,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeFloat';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_FLOAT;
|
||||
}
|
||||
}
|
58
src/Appwrite/Utopia/Response/Model/AttributeIP.php
Normal file
58
src/Appwrite/Utopia/Response/Model/AttributeIP.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeIP extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'String format.',
|
||||
'default' => APP_DATABASE_ATTRIBUTE_IP,
|
||||
'example' => APP_DATABASE_ATTRIBUTE_IP,
|
||||
'array' => false,
|
||||
'require' => true,
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => '192.0.2.0',
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_STRING,
|
||||
'format' => \APP_DATABASE_ATTRIBUTE_IP
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeIP';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_IP;
|
||||
}
|
||||
}
|
64
src/Appwrite/Utopia/Response/Model/AttributeInteger.php
Normal file
64
src/Appwrite/Utopia/Response/Model/AttributeInteger.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeInteger extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('min', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Minimum value to enforce for new documents.',
|
||||
'default' => null,
|
||||
'example' => 1,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
->addRule('max', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Maximum value to enforce for new documents.',
|
||||
'default' => null,
|
||||
'example' => 10,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => 10,
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name *
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeInteger';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_INTEGER;
|
||||
}
|
||||
}
|
56
src/Appwrite/Utopia/Response/Model/AttributeList.php
Normal file
56
src/Appwrite/Utopia/Response/Model/AttributeList.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class AttributeList extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('sum', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total sum of items in the list.',
|
||||
'default' => 0,
|
||||
'example' => 5,
|
||||
])
|
||||
->addRule('attributes', [
|
||||
'type' => [
|
||||
Response::MODEL_ATTRIBUTE_BOOLEAN,
|
||||
Response::MODEL_ATTRIBUTE_INTEGER,
|
||||
Response::MODEL_ATTRIBUTE_FLOAT,
|
||||
Response::MODEL_ATTRIBUTE_EMAIL,
|
||||
Response::MODEL_ATTRIBUTE_URL,
|
||||
Response::MODEL_ATTRIBUTE_IP,
|
||||
Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute
|
||||
],
|
||||
'description' => 'List of attributes.',
|
||||
'default' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'Attributes List';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_LIST;
|
||||
}
|
||||
}
|
55
src/Appwrite/Utopia/Response/Model/AttributeString.php
Normal file
55
src/Appwrite/Utopia/Response/Model/AttributeString.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeString extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('size', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute size.',
|
||||
'default' => 0,
|
||||
'example' => 128,
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => 'default',
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_STRING,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeString';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_STRING;
|
||||
}
|
||||
}
|
58
src/Appwrite/Utopia/Response/Model/AttributeURL.php
Normal file
58
src/Appwrite/Utopia/Response/Model/AttributeURL.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
|
||||
class AttributeURL extends Attribute
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'String format.',
|
||||
'default' => APP_DATABASE_ATTRIBUTE_URL,
|
||||
'example' => APP_DATABASE_ATTRIBUTE_URL,
|
||||
'array' => false,
|
||||
'required' => true,
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'example' => 'http://example.com',
|
||||
'array' => false,
|
||||
'require' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public array $conditions = [
|
||||
'type' => self::TYPE_STRING,
|
||||
'format' => \APP_DATABASE_ATTRIBUTE_URL
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'AttributeURL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE_URL;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Appwrite\Utopia\Response\Model;
|
|||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Collection extends Model
|
||||
{
|
||||
|
@ -35,14 +35,28 @@ class Collection extends Model
|
|||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection name.',
|
||||
'default' => '',
|
||||
'example' => '',
|
||||
'example' => 'My Collection',
|
||||
])
|
||||
->addRule('permission', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection permission model. Possible values: `document` or `collection`',
|
||||
'default' => '',
|
||||
'example' => 'document',
|
||||
])
|
||||
->addRule('attributes', [
|
||||
'type' => Response::MODEL_ATTRIBUTE,
|
||||
'type' => [
|
||||
Response::MODEL_ATTRIBUTE_BOOLEAN,
|
||||
Response::MODEL_ATTRIBUTE_INTEGER,
|
||||
Response::MODEL_ATTRIBUTE_FLOAT,
|
||||
Response::MODEL_ATTRIBUTE_EMAIL,
|
||||
Response::MODEL_ATTRIBUTE_URL,
|
||||
Response::MODEL_ATTRIBUTE_IP,
|
||||
Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute
|
||||
],
|
||||
'description' => 'Collection attributes.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('indexes', [
|
||||
'type' => Response::MODEL_INDEX,
|
||||
|
@ -51,20 +65,6 @@ class Collection extends Model
|
|||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('attributesInQueue', [
|
||||
'type' => Response::MODEL_ATTRIBUTE,
|
||||
'description' => 'Collection attributes in creation queue.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('indexesInQueue', [
|
||||
'type' => Response::MODEL_INDEX,
|
||||
'description' => 'Collection indexes in creation queue.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class Func extends Model
|
|||
])
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function status. Possible values: disabled, enabled',
|
||||
'description' => 'Function status. Possible values: `disabled`, `enabled`',
|
||||
'default' => '',
|
||||
'example' => 'enabled',
|
||||
])
|
||||
|
|
|
@ -10,11 +10,11 @@ class Index extends Model
|
|||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index ID.',
|
||||
'description' => 'Index Key.',
|
||||
'default' => '',
|
||||
'example' => '',
|
||||
'example' => 'index1',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
|
@ -22,6 +22,12 @@ class Index extends Model
|
|||
'default' => '',
|
||||
'example' => '',
|
||||
])
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index status. Possible values: `available`, `processing`, `deleting`, or `failed`',
|
||||
'default' => '',
|
||||
'example' => 'available',
|
||||
])
|
||||
->addRule('attributes', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index attributes.',
|
||||
|
|
47
src/Appwrite/Utopia/Response/Model/Metric.php
Normal file
47
src/Appwrite/Utopia/Response/Model/Metric.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class Metric extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('value', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'The value of this metric at the timestamp.',
|
||||
'default' => -1,
|
||||
'example' => 1,
|
||||
])
|
||||
->addRule('timestamp', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'The UNIX timestamp at which this metric was aggregated.',
|
||||
'default' => 0,
|
||||
'example' => 1592981250
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'Metric';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Collection
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_METRIC;
|
||||
}
|
||||
}
|
77
src/Appwrite/Utopia/Response/Model/UsageBuckets.php
Normal file
77
src/Appwrite/Utopia/Response/Model/UsageBuckets.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageBuckets extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('files.count', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of files in this bucket.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('files.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for files created.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('files.read', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for files read.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('files.update', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for files updated.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('files.delete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for files deleted.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'UsageBuckets';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_BUCKETS;
|
||||
}
|
||||
}
|
77
src/Appwrite/Utopia/Response/Model/UsageCollection.php
Normal file
77
src/Appwrite/Utopia/Response/Model/UsageCollection.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageCollection extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('documents.count', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.read', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.update', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.delete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents deleted.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'UsageCollection';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_COLLECTION;
|
||||
}
|
||||
}
|
112
src/Appwrite/Utopia/Response/Model/UsageDatabase.php
Normal file
112
src/Appwrite/Utopia/Response/Model/UsageDatabase.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageDatabase extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('documents.count', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections.count', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of collections.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.read', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.update', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents.delete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents deleted.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections created.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections.read', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections read.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections.update', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections updated.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections.delete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections delete.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'UsageDatabase';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_DATABASE;
|
||||
}
|
||||
}
|
63
src/Appwrite/Utopia/Response/Model/UsageFunctions.php
Normal file
63
src/Appwrite/Utopia/Response/Model/UsageFunctions.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageFunctions extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('functions.executions', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for function executions.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('functions.failures', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for function execution failures.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('functions.compute', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for function execution duration.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'UsageFunctions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_FUNCTIONS;
|
||||
}
|
||||
}
|
91
src/Appwrite/Utopia/Response/Model/UsageProject.php
Normal file
91
src/Appwrite/Utopia/Response/Model/UsageProject.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageProject extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('requests', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for number of requests.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('network', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for consumed bandwidth.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('functions', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for function executions.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for number of documents.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for number of collections.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('users', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for number of users.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('storage', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for the occupied storage size (in bytes).',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'UsageProject';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_PROJECT;
|
||||
}
|
||||
}
|
56
src/Appwrite/Utopia/Response/Model/UsageStorage.php
Normal file
56
src/Appwrite/Utopia/Response/Model/UsageStorage.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageStorage extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('storage', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for the occupied storage size (in bytes).',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('files', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of files.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'StorageUsage';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_STORAGE;
|
||||
}
|
||||
}
|
98
src/Appwrite/Utopia/Response/Model/UsageUsers.php
Normal file
98
src/Appwrite/Utopia/Response/Model/UsageUsers.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class UsageUsers extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('users.count', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of users.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('users.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for users created.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('users.read', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for users read.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('users.update', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for users updated.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('users.delete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for users deleted.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('sessions.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for sessions created.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('sessions.provider.create', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('sessions.delete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for sessions deleted.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'UsageUsers';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_USAGE_USERS;
|
||||
}
|
||||
}
|
23
tests/e2e/Scopes/SideConsole.php
Normal file
23
tests/e2e/Scopes/SideConsole.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\E2E\Scopes;
|
||||
|
||||
trait SideConsole
|
||||
{
|
||||
public function getHeaders():array
|
||||
{
|
||||
return [
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console='. $this->getRoot()['session'],
|
||||
'x-appwrite-mode' => 'admin'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSide()
|
||||
{
|
||||
return 'console';
|
||||
}
|
||||
}
|
|
@ -342,7 +342,7 @@ class AccountCustomClientTest extends Scope
|
|||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
$this->assertEquals($response['headers']['status-code'], 409);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
|
|
|
@ -20,6 +20,7 @@ trait DatabaseBase
|
|||
'name' => 'Movies',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'permission' => 'document',
|
||||
]);
|
||||
|
||||
$this->assertEquals($movies['headers']['status-code'], 201);
|
||||
|
@ -43,8 +44,6 @@ trait DatabaseBase
|
|||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$releaseYear = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
@ -54,8 +53,6 @@ trait DatabaseBase
|
|||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
@ -68,26 +65,25 @@ trait DatabaseBase
|
|||
]);
|
||||
|
||||
$this->assertEquals($title['headers']['status-code'], 201);
|
||||
$this->assertEquals($title['body']['$id'], 'title');
|
||||
$this->assertEquals($title['body']['key'], 'title');
|
||||
$this->assertEquals($title['body']['type'], 'string');
|
||||
$this->assertEquals($title['body']['size'], 256);
|
||||
$this->assertEquals($title['body']['required'], true);
|
||||
|
||||
$this->assertEquals($releaseYear['headers']['status-code'], 201);
|
||||
$this->assertEquals($releaseYear['body']['$id'], 'releaseYear');
|
||||
$this->assertEquals($releaseYear['body']['key'], 'releaseYear');
|
||||
$this->assertEquals($releaseYear['body']['type'], 'integer');
|
||||
$this->assertEquals($releaseYear['body']['size'], 0);
|
||||
$this->assertEquals($releaseYear['body']['required'], true);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
$this->assertEquals($actors['body']['$id'], 'actors');
|
||||
$this->assertEquals($actors['body']['key'], 'actors');
|
||||
$this->assertEquals($actors['body']['type'], 'string');
|
||||
$this->assertEquals($actors['body']['size'], 256);
|
||||
$this->assertEquals($actors['body']['required'], false);
|
||||
$this->assertEquals($actors['body']['array'], true);
|
||||
|
||||
// wait for database worker to create attributes
|
||||
sleep(5);
|
||||
sleep(2);
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -95,13 +91,425 @@ trait DatabaseBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertIsArray($movies['body']['attributesInQueue']);
|
||||
$this->assertCount(0, $movies['body']['attributesInQueue']);
|
||||
$this->assertIsArray($movies['body']['attributes']);
|
||||
$this->assertCount(3, $movies['body']['attributes']);
|
||||
$this->assertEquals($movies['body']['attributes'][0]['$id'], $title['body']['$id']);
|
||||
$this->assertEquals($movies['body']['attributes'][1]['$id'], $releaseYear['body']['$id']);
|
||||
$this->assertEquals($movies['body']['attributes'][2]['$id'], $actors['body']['$id']);
|
||||
$this->assertEquals($movies['body']['attributes'][0]['key'], $title['body']['key']);
|
||||
$this->assertEquals($movies['body']['attributes'][1]['key'], $releaseYear['body']['key']);
|
||||
$this->assertEquals($movies['body']['attributes'][2]['key'], $actors['body']['key']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
public function testAttributeResponseModels(array $data): array
|
||||
{
|
||||
$collection= $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => 'unique()',
|
||||
'name' => 'Response Models',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'permission' => 'document',
|
||||
]);
|
||||
|
||||
$this->assertEquals($collection['headers']['status-code'], 201);
|
||||
$this->assertEquals($collection['body']['name'], 'Response Models');
|
||||
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
$string = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'string',
|
||||
'size' => 16,
|
||||
'required' => false,
|
||||
'default' => 'default',
|
||||
]);
|
||||
|
||||
$email = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/email', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'email',
|
||||
'required' => false,
|
||||
'default' => 'default@example.com',
|
||||
]);
|
||||
|
||||
$ip = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/ip', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'ip',
|
||||
'required' => false,
|
||||
'default' => '192.0.2.0',
|
||||
]);
|
||||
|
||||
$url = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/url', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'url',
|
||||
'required' => false,
|
||||
'default' => 'http://example.com',
|
||||
]);
|
||||
|
||||
$integer = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'integer',
|
||||
'required' => false,
|
||||
'min' => 1,
|
||||
'max' => 5,
|
||||
'default' => 3
|
||||
]);
|
||||
|
||||
$float = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/float', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'float',
|
||||
'required' => false,
|
||||
'min' => 1.5,
|
||||
'max' => 5.5,
|
||||
'default' => 3.5
|
||||
]);
|
||||
|
||||
$boolean = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/boolean', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'attributeId' => 'boolean',
|
||||
'required' => false,
|
||||
'default' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $string['headers']['status-code']);
|
||||
$this->assertEquals('string', $string['body']['key']);
|
||||
$this->assertEquals('string', $string['body']['type']);
|
||||
$this->assertEquals('processing', $string['body']['status']);
|
||||
$this->assertEquals(false, $string['body']['required']);
|
||||
$this->assertEquals(false, $string['body']['array']);
|
||||
$this->assertEquals(16, $string['body']['size']);
|
||||
$this->assertEquals('default', $string['body']['default']);
|
||||
|
||||
$this->assertEquals(201, $email['headers']['status-code']);
|
||||
$this->assertEquals('email', $email['body']['key']);
|
||||
$this->assertEquals('string', $email['body']['type']);
|
||||
$this->assertEquals('processing', $email['body']['status']);
|
||||
$this->assertEquals(false, $email['body']['required']);
|
||||
$this->assertEquals(false, $email['body']['array']);
|
||||
$this->assertEquals('email', $email['body']['format']);
|
||||
$this->assertEquals('default@example.com', $email['body']['default']);
|
||||
|
||||
$this->assertEquals(201, $ip['headers']['status-code']);
|
||||
$this->assertEquals('ip', $ip['body']['key']);
|
||||
$this->assertEquals('string', $ip['body']['type']);
|
||||
$this->assertEquals('processing', $ip['body']['status']);
|
||||
$this->assertEquals(false, $ip['body']['required']);
|
||||
$this->assertEquals(false, $ip['body']['array']);
|
||||
$this->assertEquals('ip', $ip['body']['format']);
|
||||
$this->assertEquals('192.0.2.0', $ip['body']['default']);
|
||||
|
||||
$this->assertEquals(201, $url['headers']['status-code']);
|
||||
$this->assertEquals('url', $url['body']['key']);
|
||||
$this->assertEquals('string', $url['body']['type']);
|
||||
$this->assertEquals('processing', $url['body']['status']);
|
||||
$this->assertEquals(false, $url['body']['required']);
|
||||
$this->assertEquals(false, $url['body']['array']);
|
||||
$this->assertEquals('url', $url['body']['format']);
|
||||
$this->assertEquals('http://example.com', $url['body']['default']);
|
||||
|
||||
$this->assertEquals(201, $integer['headers']['status-code']);
|
||||
$this->assertEquals('integer', $integer['body']['key']);
|
||||
$this->assertEquals('integer', $integer['body']['type']);
|
||||
$this->assertEquals('processing', $integer['body']['status']);
|
||||
$this->assertEquals(false, $integer['body']['required']);
|
||||
$this->assertEquals(false, $integer['body']['array']);
|
||||
$this->assertEquals(1, $integer['body']['min']);
|
||||
$this->assertEquals(5, $integer['body']['max']);
|
||||
$this->assertEquals(3, $integer['body']['default']);
|
||||
|
||||
$this->assertEquals(201, $float['headers']['status-code']);
|
||||
$this->assertEquals('float', $float['body']['key']);
|
||||
$this->assertEquals('double', $float['body']['type']);
|
||||
$this->assertEquals('processing', $float['body']['status']);
|
||||
$this->assertEquals(false, $float['body']['required']);
|
||||
$this->assertEquals(false, $float['body']['array']);
|
||||
$this->assertEquals(1.5, $float['body']['min']);
|
||||
$this->assertEquals(5.5, $float['body']['max']);
|
||||
$this->assertEquals(3.5, $float['body']['default']);
|
||||
|
||||
$this->assertEquals(201, $boolean['headers']['status-code']);
|
||||
$this->assertEquals('boolean', $boolean['body']['key']);
|
||||
$this->assertEquals('boolean', $boolean['body']['type']);
|
||||
$this->assertEquals('processing', $boolean['body']['status']);
|
||||
$this->assertEquals(false, $boolean['body']['required']);
|
||||
$this->assertEquals(false, $boolean['body']['array']);
|
||||
$this->assertEquals(true, $boolean['body']['default']);
|
||||
|
||||
// wait for database worker to create attributes
|
||||
sleep(5);
|
||||
|
||||
$stringResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$string['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$emailResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$email['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$ipResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$ip['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$urlResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$url['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$integerResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$integer['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$floatResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$float['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$booleanResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$boolean['body']['key']}",array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $stringResponse['headers']['status-code']);
|
||||
$this->assertEquals($string['body']['key'], $stringResponse['body']['key']);
|
||||
$this->assertEquals($string['body']['type'], $stringResponse['body']['type']);
|
||||
$this->assertEquals('available', $stringResponse['body']['status']);
|
||||
$this->assertEquals($string['body']['required'], $stringResponse['body']['required']);
|
||||
$this->assertEquals($string['body']['array'], $stringResponse['body']['array']);
|
||||
$this->assertEquals(16, $stringResponse['body']['size']);
|
||||
$this->assertEquals($string['body']['default'], $stringResponse['body']['default']);
|
||||
|
||||
$this->assertEquals(200, $emailResponse['headers']['status-code']);
|
||||
$this->assertEquals($email['body']['key'], $emailResponse['body']['key']);
|
||||
$this->assertEquals($email['body']['type'], $emailResponse['body']['type']);
|
||||
$this->assertEquals('available', $emailResponse['body']['status']);
|
||||
$this->assertEquals($email['body']['required'], $emailResponse['body']['required']);
|
||||
$this->assertEquals($email['body']['array'], $emailResponse['body']['array']);
|
||||
$this->assertEquals($email['body']['format'], $emailResponse['body']['format']);
|
||||
$this->assertEquals($email['body']['default'], $emailResponse['body']['default']);
|
||||
|
||||
$this->assertEquals(200, $ipResponse['headers']['status-code']);
|
||||
$this->assertEquals($ip['body']['key'], $ipResponse['body']['key']);
|
||||
$this->assertEquals($ip['body']['type'], $ipResponse['body']['type']);
|
||||
$this->assertEquals('available', $ipResponse['body']['status']);
|
||||
$this->assertEquals($ip['body']['required'], $ipResponse['body']['required']);
|
||||
$this->assertEquals($ip['body']['array'], $ipResponse['body']['array']);
|
||||
$this->assertEquals($ip['body']['format'], $ipResponse['body']['format']);
|
||||
$this->assertEquals($ip['body']['default'], $ipResponse['body']['default']);
|
||||
|
||||
$this->assertEquals(200, $urlResponse['headers']['status-code']);
|
||||
$this->assertEquals($url['body']['key'], $urlResponse['body']['key']);
|
||||
$this->assertEquals($url['body']['type'], $urlResponse['body']['type']);
|
||||
$this->assertEquals('available', $urlResponse['body']['status']);
|
||||
$this->assertEquals($url['body']['required'], $urlResponse['body']['required']);
|
||||
$this->assertEquals($url['body']['array'], $urlResponse['body']['array']);
|
||||
$this->assertEquals($url['body']['format'], $urlResponse['body']['format']);
|
||||
$this->assertEquals($url['body']['default'], $urlResponse['body']['default']);
|
||||
|
||||
$this->assertEquals(200, $integerResponse['headers']['status-code']);
|
||||
$this->assertEquals($integer['body']['key'], $integerResponse['body']['key']);
|
||||
$this->assertEquals($integer['body']['type'], $integerResponse['body']['type']);
|
||||
$this->assertEquals('available', $integerResponse['body']['status']);
|
||||
$this->assertEquals($integer['body']['required'], $integerResponse['body']['required']);
|
||||
$this->assertEquals($integer['body']['array'], $integerResponse['body']['array']);
|
||||
$this->assertEquals($integer['body']['min'], $integerResponse['body']['min']);
|
||||
$this->assertEquals($integer['body']['max'], $integerResponse['body']['max']);
|
||||
$this->assertEquals($integer['body']['default'], $integerResponse['body']['default']);
|
||||
|
||||
$this->assertEquals(200, $floatResponse['headers']['status-code']);
|
||||
$this->assertEquals($float['body']['key'], $floatResponse['body']['key']);
|
||||
$this->assertEquals($float['body']['type'], $floatResponse['body']['type']);
|
||||
$this->assertEquals('available', $floatResponse['body']['status']);
|
||||
$this->assertEquals($float['body']['required'], $floatResponse['body']['required']);
|
||||
$this->assertEquals($float['body']['array'], $floatResponse['body']['array']);
|
||||
$this->assertEquals($float['body']['min'], $floatResponse['body']['min']);
|
||||
$this->assertEquals($float['body']['max'], $floatResponse['body']['max']);
|
||||
$this->assertEquals($float['body']['default'], $floatResponse['body']['default']);
|
||||
|
||||
$this->assertEquals(200, $booleanResponse['headers']['status-code']);
|
||||
$this->assertEquals($boolean['body']['key'], $booleanResponse['body']['key']);
|
||||
$this->assertEquals($boolean['body']['type'], $booleanResponse['body']['type']);
|
||||
$this->assertEquals('available', $booleanResponse['body']['status']);
|
||||
$this->assertEquals($boolean['body']['required'], $booleanResponse['body']['required']);
|
||||
$this->assertEquals($boolean['body']['array'], $booleanResponse['body']['array']);
|
||||
$this->assertEquals($boolean['body']['default'], $booleanResponse['body']['default']);
|
||||
|
||||
$attributes = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $attributes['headers']['status-code']);
|
||||
$this->assertEquals(7, $attributes['body']['sum']);
|
||||
|
||||
$attributes = $attributes['body']['attributes'];
|
||||
|
||||
$this->assertIsArray($attributes);
|
||||
$this->assertCount(7, $attributes);
|
||||
|
||||
$this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']);
|
||||
$this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']);
|
||||
$this->assertEquals($stringResponse['body']['status'], $attributes[0]['status']);
|
||||
$this->assertEquals($stringResponse['body']['required'], $attributes[0]['required']);
|
||||
$this->assertEquals($stringResponse['body']['array'], $attributes[0]['array']);
|
||||
$this->assertEquals($stringResponse['body']['size'], $attributes[0]['size']);
|
||||
$this->assertEquals($stringResponse['body']['default'], $attributes[0]['default']);
|
||||
|
||||
$this->assertEquals($emailResponse['body']['key'], $attributes[1]['key']);
|
||||
$this->assertEquals($emailResponse['body']['type'], $attributes[1]['type']);
|
||||
$this->assertEquals($emailResponse['body']['status'], $attributes[1]['status']);
|
||||
$this->assertEquals($emailResponse['body']['required'], $attributes[1]['required']);
|
||||
$this->assertEquals($emailResponse['body']['array'], $attributes[1]['array']);
|
||||
$this->assertEquals($emailResponse['body']['default'], $attributes[1]['default']);
|
||||
$this->assertEquals($emailResponse['body']['format'], $attributes[1]['format']);
|
||||
|
||||
$this->assertEquals($ipResponse['body']['key'], $attributes[2]['key']);
|
||||
$this->assertEquals($ipResponse['body']['type'], $attributes[2]['type']);
|
||||
$this->assertEquals($ipResponse['body']['status'], $attributes[2]['status']);
|
||||
$this->assertEquals($ipResponse['body']['required'], $attributes[2]['required']);
|
||||
$this->assertEquals($ipResponse['body']['array'], $attributes[2]['array']);
|
||||
$this->assertEquals($ipResponse['body']['default'], $attributes[2]['default']);
|
||||
$this->assertEquals($ipResponse['body']['format'], $attributes[2]['format']);
|
||||
|
||||
$this->assertEquals($urlResponse['body']['key'], $attributes[3]['key']);
|
||||
$this->assertEquals($urlResponse['body']['type'], $attributes[3]['type']);
|
||||
$this->assertEquals($urlResponse['body']['status'], $attributes[3]['status']);
|
||||
$this->assertEquals($urlResponse['body']['required'], $attributes[3]['required']);
|
||||
$this->assertEquals($urlResponse['body']['array'], $attributes[3]['array']);
|
||||
$this->assertEquals($urlResponse['body']['default'], $attributes[3]['default']);
|
||||
$this->assertEquals($urlResponse['body']['format'], $attributes[3]['format']);
|
||||
|
||||
$this->assertEquals($integerResponse['body']['key'], $attributes[4]['key']);
|
||||
$this->assertEquals($integerResponse['body']['type'], $attributes[4]['type']);
|
||||
$this->assertEquals($integerResponse['body']['status'], $attributes[4]['status']);
|
||||
$this->assertEquals($integerResponse['body']['required'], $attributes[4]['required']);
|
||||
$this->assertEquals($integerResponse['body']['array'], $attributes[4]['array']);
|
||||
$this->assertEquals($integerResponse['body']['default'], $attributes[4]['default']);
|
||||
$this->assertEquals($integerResponse['body']['min'], $attributes[4]['min']);
|
||||
$this->assertEquals($integerResponse['body']['max'], $attributes[4]['max']);
|
||||
|
||||
$this->assertEquals($floatResponse['body']['key'], $attributes[5]['key']);
|
||||
$this->assertEquals($floatResponse['body']['type'], $attributes[5]['type']);
|
||||
$this->assertEquals($floatResponse['body']['status'], $attributes[5]['status']);
|
||||
$this->assertEquals($floatResponse['body']['required'], $attributes[5]['required']);
|
||||
$this->assertEquals($floatResponse['body']['array'], $attributes[5]['array']);
|
||||
$this->assertEquals($floatResponse['body']['default'], $attributes[5]['default']);
|
||||
$this->assertEquals($floatResponse['body']['min'], $attributes[5]['min']);
|
||||
$this->assertEquals($floatResponse['body']['max'], $attributes[5]['max']);
|
||||
|
||||
$this->assertEquals($booleanResponse['body']['key'], $attributes[6]['key']);
|
||||
$this->assertEquals($booleanResponse['body']['type'], $attributes[6]['type']);
|
||||
$this->assertEquals($booleanResponse['body']['status'], $attributes[6]['status']);
|
||||
$this->assertEquals($booleanResponse['body']['required'], $attributes[6]['required']);
|
||||
$this->assertEquals($booleanResponse['body']['array'], $attributes[6]['array']);
|
||||
$this->assertEquals($booleanResponse['body']['default'], $attributes[6]['default']);
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
|
||||
$attributes = $collection['body']['attributes'];
|
||||
|
||||
$this->assertIsArray($attributes);
|
||||
$this->assertCount(7, $attributes);
|
||||
|
||||
$this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']);
|
||||
$this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']);
|
||||
$this->assertEquals($stringResponse['body']['status'], $attributes[0]['status']);
|
||||
$this->assertEquals($stringResponse['body']['required'], $attributes[0]['required']);
|
||||
$this->assertEquals($stringResponse['body']['array'], $attributes[0]['array']);
|
||||
$this->assertEquals($stringResponse['body']['size'], $attributes[0]['size']);
|
||||
$this->assertEquals($stringResponse['body']['default'], $attributes[0]['default']);
|
||||
|
||||
$this->assertEquals($emailResponse['body']['key'], $attributes[1]['key']);
|
||||
$this->assertEquals($emailResponse['body']['type'], $attributes[1]['type']);
|
||||
$this->assertEquals($emailResponse['body']['status'], $attributes[1]['status']);
|
||||
$this->assertEquals($emailResponse['body']['required'], $attributes[1]['required']);
|
||||
$this->assertEquals($emailResponse['body']['array'], $attributes[1]['array']);
|
||||
$this->assertEquals($emailResponse['body']['default'], $attributes[1]['default']);
|
||||
$this->assertEquals($emailResponse['body']['format'], $attributes[1]['format']);
|
||||
|
||||
$this->assertEquals($ipResponse['body']['key'], $attributes[2]['key']);
|
||||
$this->assertEquals($ipResponse['body']['type'], $attributes[2]['type']);
|
||||
$this->assertEquals($ipResponse['body']['status'], $attributes[2]['status']);
|
||||
$this->assertEquals($ipResponse['body']['required'], $attributes[2]['required']);
|
||||
$this->assertEquals($ipResponse['body']['array'], $attributes[2]['array']);
|
||||
$this->assertEquals($ipResponse['body']['default'], $attributes[2]['default']);
|
||||
$this->assertEquals($ipResponse['body']['format'], $attributes[2]['format']);
|
||||
|
||||
$this->assertEquals($urlResponse['body']['key'], $attributes[3]['key']);
|
||||
$this->assertEquals($urlResponse['body']['type'], $attributes[3]['type']);
|
||||
$this->assertEquals($urlResponse['body']['status'], $attributes[3]['status']);
|
||||
$this->assertEquals($urlResponse['body']['required'], $attributes[3]['required']);
|
||||
$this->assertEquals($urlResponse['body']['array'], $attributes[3]['array']);
|
||||
$this->assertEquals($urlResponse['body']['default'], $attributes[3]['default']);
|
||||
$this->assertEquals($urlResponse['body']['format'], $attributes[3]['format']);
|
||||
|
||||
$this->assertEquals($integerResponse['body']['key'], $attributes[4]['key']);
|
||||
$this->assertEquals($integerResponse['body']['type'], $attributes[4]['type']);
|
||||
$this->assertEquals($integerResponse['body']['status'], $attributes[4]['status']);
|
||||
$this->assertEquals($integerResponse['body']['required'], $attributes[4]['required']);
|
||||
$this->assertEquals($integerResponse['body']['array'], $attributes[4]['array']);
|
||||
$this->assertEquals($integerResponse['body']['default'], $attributes[4]['default']);
|
||||
$this->assertEquals($integerResponse['body']['min'], $attributes[4]['min']);
|
||||
$this->assertEquals($integerResponse['body']['max'], $attributes[4]['max']);
|
||||
|
||||
$this->assertEquals($floatResponse['body']['key'], $attributes[5]['key']);
|
||||
$this->assertEquals($floatResponse['body']['type'], $attributes[5]['type']);
|
||||
$this->assertEquals($floatResponse['body']['status'], $attributes[5]['status']);
|
||||
$this->assertEquals($floatResponse['body']['required'], $attributes[5]['required']);
|
||||
$this->assertEquals($floatResponse['body']['array'], $attributes[5]['array']);
|
||||
$this->assertEquals($floatResponse['body']['default'], $attributes[5]['default']);
|
||||
$this->assertEquals($floatResponse['body']['min'], $attributes[5]['min']);
|
||||
$this->assertEquals($floatResponse['body']['max'], $attributes[5]['max']);
|
||||
|
||||
$this->assertEquals($booleanResponse['body']['key'], $attributes[6]['key']);
|
||||
$this->assertEquals($booleanResponse['body']['type'], $attributes[6]['type']);
|
||||
$this->assertEquals($booleanResponse['body']['status'], $attributes[6]['status']);
|
||||
$this->assertEquals($booleanResponse['body']['required'], $attributes[6]['required']);
|
||||
$this->assertEquals($booleanResponse['body']['array'], $attributes[6]['array']);
|
||||
$this->assertEquals($booleanResponse['body']['default'], $attributes[6]['default']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
@ -122,13 +530,13 @@ trait DatabaseBase
|
|||
]);
|
||||
|
||||
$this->assertEquals($titleIndex['headers']['status-code'], 201);
|
||||
$this->assertEquals($titleIndex['body']['$id'], 'titleIndex');
|
||||
$this->assertEquals($titleIndex['body']['key'], 'titleIndex');
|
||||
$this->assertEquals($titleIndex['body']['type'], 'fulltext');
|
||||
$this->assertCount(1, $titleIndex['body']['attributes']);
|
||||
$this->assertEquals($titleIndex['body']['attributes'][0], 'title');
|
||||
|
||||
// wait for database worker to create index
|
||||
sleep(5);
|
||||
sleep(2);
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -138,7 +546,7 @@ trait DatabaseBase
|
|||
|
||||
$this->assertIsArray($movies['body']['indexes']);
|
||||
$this->assertCount(1, $movies['body']['indexes']);
|
||||
$this->assertEquals($movies['body']['indexes'][0]['$id'], $titleIndex['body']['$id']);
|
||||
$this->assertEquals($movies['body']['indexes'][0]['key'], $titleIndex['body']['key']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
@ -243,8 +651,8 @@ trait DatabaseBase
|
|||
$this->assertCount(1, $document3['body']['$read']);
|
||||
$this->assertCount(1, $document3['body']['$write']);
|
||||
$this->assertCount(2, $document3['body']['actors']);
|
||||
$this->assertEquals($document2['body']['actors'][0], 'Tom Holland');
|
||||
$this->assertEquals($document2['body']['actors'][1], 'Zendaya Maree Stoermer');
|
||||
$this->assertEquals($document3['body']['actors'][0], 'Tom Holland');
|
||||
$this->assertEquals($document3['body']['actors'][1], 'Zendaya Maree Stoermer');
|
||||
|
||||
$this->assertEquals($document4['headers']['status-code'], 400);
|
||||
|
||||
|
@ -264,6 +672,7 @@ trait DatabaseBase
|
|||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
|
||||
$this->assertEquals(2019, $documents['body']['documents'][2]['releaseYear']);
|
||||
|
@ -277,6 +686,7 @@ trait DatabaseBase
|
|||
'orderTypes' => ['DESC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals(1944, $documents['body']['documents'][2]['releaseYear']);
|
||||
$this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
|
||||
$this->assertEquals(2019, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -298,6 +708,7 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($base['headers']['status-code'], 200);
|
||||
$this->assertEquals('Captain America', $base['body']['documents'][0]['title']);
|
||||
$this->assertEquals('Spider-Man: Far From Home', $base['body']['documents'][1]['title']);
|
||||
$this->assertEquals('Spider-Man: Homecoming', $base['body']['documents'][2]['title']);
|
||||
|
@ -310,6 +721,7 @@ trait DatabaseBase
|
|||
'after' => $base['body']['documents'][0]['$id']
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals($base['body']['documents'][1]['$id'], $documents['body']['documents'][0]['$id']);
|
||||
$this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][1]['$id']);
|
||||
$this->assertCount(2, $documents['body']['documents']);
|
||||
|
@ -321,6 +733,7 @@ trait DatabaseBase
|
|||
'after' => $base['body']['documents'][2]['$id']
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEmpty($documents['body']['documents']);
|
||||
|
||||
/**
|
||||
|
@ -334,6 +747,7 @@ trait DatabaseBase
|
|||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($base['headers']['status-code'], 200);
|
||||
$this->assertEquals(1944, $base['body']['documents'][0]['releaseYear']);
|
||||
$this->assertEquals(2017, $base['body']['documents'][1]['releaseYear']);
|
||||
$this->assertEquals(2019, $base['body']['documents'][2]['releaseYear']);
|
||||
|
@ -348,6 +762,7 @@ trait DatabaseBase
|
|||
'after' => $base['body']['documents'][1]['$id']
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][0]['$id']);
|
||||
$this->assertCount(1, $documents['body']['documents']);
|
||||
|
||||
|
@ -362,6 +777,7 @@ trait DatabaseBase
|
|||
'orderTypes' => ['DESC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($base['headers']['status-code'], 200);
|
||||
$this->assertEquals(1944, $base['body']['documents'][2]['releaseYear']);
|
||||
$this->assertEquals(2017, $base['body']['documents'][1]['releaseYear']);
|
||||
$this->assertEquals(2019, $base['body']['documents'][0]['releaseYear']);
|
||||
|
@ -376,6 +792,7 @@ trait DatabaseBase
|
|||
'after' => $base['body']['documents'][1]['$id']
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][0]['$id']);
|
||||
$this->assertCount(1, $documents['body']['documents']);
|
||||
|
||||
|
@ -408,6 +825,7 @@ trait DatabaseBase
|
|||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertCount(1, $documents['body']['documents']);
|
||||
|
||||
|
@ -421,6 +839,7 @@ trait DatabaseBase
|
|||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($documents['headers']['status-code'], 200);
|
||||
$this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertEquals(2019, $documents['body']['documents'][1]['releaseYear']);
|
||||
$this->assertCount(2, $documents['body']['documents']);
|
||||
|
@ -431,41 +850,46 @@ trait DatabaseBase
|
|||
/**
|
||||
* @depends testCreateDocument
|
||||
*/
|
||||
public function testDocumentsListSuccessSearch(array $data):array
|
||||
{
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => ['title.search("Captain America")'],
|
||||
]);
|
||||
// public function testDocumentsListSuccessSearch(array $data):array
|
||||
// {
|
||||
// $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'queries' => ['title.search("Captain America")'],
|
||||
// ]);
|
||||
|
||||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertCount(1, $documents['body']['documents']);
|
||||
// var_dump($documents);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => ['title.search("Homecoming")'],
|
||||
]);
|
||||
// $this->assertEquals($documents['headers']['status-code'], 200);
|
||||
// $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
// $this->assertCount(1, $documents['body']['documents']);
|
||||
|
||||
$this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertCount(1, $documents['body']['documents']);
|
||||
// $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'queries' => ['title.search("Homecoming")'],
|
||||
// ]);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => ['title.search("spider")'],
|
||||
]);
|
||||
// $this->assertEquals($documents['headers']['status-code'], 200);
|
||||
// $this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']);
|
||||
// $this->assertCount(1, $documents['body']['documents']);
|
||||
|
||||
$this->assertEquals(2019, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
|
||||
$this->assertCount(2, $documents['body']['documents']);
|
||||
// $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'queries' => ['title.search("spider")'],
|
||||
// ]);
|
||||
|
||||
return [];
|
||||
}
|
||||
// $this->assertEquals($documents['headers']['status-code'], 200);
|
||||
// $this->assertEquals(2019, $documents['body']['documents'][0]['releaseYear']);
|
||||
// $this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
|
||||
// $this->assertCount(2, $documents['body']['documents']);
|
||||
|
||||
// return [];
|
||||
// }
|
||||
// TODO@kodumbeats test for empty searches and misformatted queries
|
||||
|
||||
/**
|
||||
|
@ -626,6 +1050,7 @@ trait DatabaseBase
|
|||
'name' => 'invalidDocumentStructure',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'permission' => 'document',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
|
@ -742,7 +1167,7 @@ trait DatabaseBase
|
|||
// $this->assertEquals('Minimum value must be lesser than maximum value', $invalidRange['body']['message']);
|
||||
|
||||
// wait for worker to add attributes
|
||||
sleep(15);
|
||||
sleep(2);
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -751,7 +1176,6 @@ trait DatabaseBase
|
|||
]), []);
|
||||
|
||||
$this->assertCount(7, $collection['body']['attributes']);
|
||||
// $this->assertCount(0, $collection['body']['attributesInQueue']);
|
||||
|
||||
/**
|
||||
* Test for successful validation
|
||||
|
@ -937,7 +1361,6 @@ trait DatabaseBase
|
|||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals(400, $badEmail['headers']['status-code']);
|
||||
$this->assertEquals(400, $badIp['headers']['status-code']);
|
||||
$this->assertEquals(400, $badUrl['headers']['status-code']);
|
||||
|
@ -950,8 +1373,8 @@ trait DatabaseBase
|
|||
$this->assertEquals('Invalid document structure: Attribute "url" has invalid format. Value must be a valid URL', $badUrl['body']['message']);
|
||||
$this->assertEquals('Invalid document structure: Attribute "range" has invalid format. Value must be a valid range between 1 and 10', $badRange['body']['message']);
|
||||
$this->assertEquals('Invalid document structure: Attribute "floatRange" has invalid format. Value must be a valid range between 1 and 1', $badFloatRange['body']['message']);
|
||||
$this->assertEquals('Invalid document structure: Attribute "upperBound" has invalid format. Value must be a valid range between inf and 10', $tooHigh['body']['message']);
|
||||
$this->assertEquals('Invalid document structure: Attribute "lowerBound" has invalid format. Value must be a valid range between 5 and inf', $tooLow['body']['message']);
|
||||
$this->assertEquals('Invalid document structure: Attribute "upperBound" has invalid format. Value must be a valid range between -9,223,372,036,854,775,808 and 10', $tooHigh['body']['message']);
|
||||
$this->assertEquals('Invalid document structure: Attribute "lowerBound" has invalid format. Value must be a valid range between 5 and 9,223,372,036,854,775,808', $tooLow['body']['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1079,4 +1502,86 @@ trait DatabaseBase
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testDefaultPermissions
|
||||
*/
|
||||
public function testUniqueIndexDuplicate(array $data): array
|
||||
{
|
||||
$uniqueIndex = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'indexId' => 'unique_title',
|
||||
'type' => 'unique',
|
||||
'attributes' => ['title'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($uniqueIndex['headers']['status-code'], 201);
|
||||
|
||||
sleep(2);
|
||||
|
||||
// test for failure
|
||||
$duplicate = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => 'unique()',
|
||||
'data' => [
|
||||
'title' => 'Captain America',
|
||||
'releaseYear' => 1944,
|
||||
'actors' => [
|
||||
'Chris Evans',
|
||||
'Samuel Jackson',
|
||||
]
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
]);
|
||||
|
||||
$this->assertEquals(409, $duplicate['headers']['status-code']);
|
||||
|
||||
// Test for exception when updating document to conflict
|
||||
$document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => 'unique()',
|
||||
'data' => [
|
||||
'title' => 'Captain America 5',
|
||||
'releaseYear' => 1944,
|
||||
'actors' => [
|
||||
'Chris Evans',
|
||||
'Samuel Jackson',
|
||||
]
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $document['headers']['status-code']);
|
||||
|
||||
// Test for exception when updating document to conflict
|
||||
$duplicate = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $data['moviesId'] . '/documents/' . $document['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => 'unique()',
|
||||
'data' => [
|
||||
'title' => 'Captain America',
|
||||
'releaseYear' => 1944,
|
||||
'actors' => [
|
||||
'Chris Evans',
|
||||
'Samuel Jackson',
|
||||
]
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
]);
|
||||
|
||||
$this->assertEquals(409, $duplicate['headers']['status-code']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
125
tests/e2e/Services/Database/DatabaseConsoleClientTest.php
Normal file
125
tests/e2e/Services/Database/DatabaseConsoleClientTest.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Database;
|
||||
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\SideConsole;
|
||||
|
||||
class DatabaseConsoleClientTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideConsole;
|
||||
|
||||
public function testCreateCollection():array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'collectionId' => 'unique()',
|
||||
'name' => 'Movies',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'permission' => 'document',
|
||||
]);
|
||||
|
||||
$this->assertEquals($movies['headers']['status-code'], 201);
|
||||
$this->assertEquals($movies['body']['name'], 'Movies');
|
||||
|
||||
return ['moviesId' => $movies['body']['$id']];
|
||||
}
|
||||
|
||||
public function testGetDatabaseUsage()
|
||||
{
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/database/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '32h'
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/database/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertEquals(count($response['body']), 11);
|
||||
$this->assertEquals($response['body']['range'], '24h');
|
||||
$this->assertIsArray($response['body']['documents.count']);
|
||||
$this->assertIsArray($response['body']['collections.count']);
|
||||
$this->assertIsArray($response['body']['documents.create']);
|
||||
$this->assertIsArray($response['body']['documents.read']);
|
||||
$this->assertIsArray($response['body']['documents.update']);
|
||||
$this->assertIsArray($response['body']['documents.delete']);
|
||||
$this->assertIsArray($response['body']['collections.create']);
|
||||
$this->assertIsArray($response['body']['collections.read']);
|
||||
$this->assertIsArray($response['body']['collections.update']);
|
||||
$this->assertIsArray($response['body']['collections.delete']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
*/
|
||||
public function testGetCollectionUsage(array $data)
|
||||
{
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/database/'.$data['moviesId'].'/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '32h'
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/database/randomCollectionId/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 404);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/database/'.$data['moviesId'].'/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertEquals(count($response['body']), 6);
|
||||
$this->assertEquals($response['body']['range'], '24h');
|
||||
$this->assertIsArray($response['body']['documents.count']);
|
||||
$this->assertIsArray($response['body']['documents.create']);
|
||||
$this->assertIsArray($response['body']['documents.read']);
|
||||
$this->assertIsArray($response['body']['documents.update']);
|
||||
$this->assertIsArray($response['body']['documents.delete']);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue