1
0
Fork 0
mirror of synced 2024-05-19 12:12:36 +12:00

Merge branch '0.8.x' of https://github.com/appwrite/appwrite into feat-265-realtime

This commit is contained in:
Torsten Dittmann 2021-05-04 17:21:10 +02:00
commit 3d4c3741a2
181 changed files with 2175 additions and 2450 deletions

2
.env
View file

@ -25,7 +25,7 @@ _APP_INFLUXDB_PORT=8086
_APP_STATSD_HOST=telegraf
_APP_STATSD_PORT=8125
_APP_SMTP_HOST=maildev
_APP_SMTP_PORT=25
_APP_SMTP_PORT=1025
_APP_SMTP_SECURE=
_APP_SMTP_USERNAME=
_APP_SMTP_PASSWORD=

View file

@ -2,6 +2,7 @@ dist: xenial
arch:
- amd64
- arm64
os: linux
@ -10,9 +11,6 @@ language: shell
notifications:
email:
- team@appwrite.io
services:
- docker
before_install:
- curl -fsSL https://get.docker.com | sh
@ -27,6 +25,9 @@ before_install:
- docker --version
- docker buildx create --use
- chmod -R u+x ./.travis-ci
- export COMPOSE_INTERACTIVE_NO_CLI=1
# Only pass a single runtime for CI stability
- echo "_APP_FUNCTIONS_ENVS=php-8.0" >> .env
install:
- docker-compose up -d

View file

@ -3,23 +3,43 @@
## Features
- Realtime Integration ([RFC-014](https://github.com/appwrite/rfc/blob/main/014-realtime-api.md), #948)
- Added Anonymous Login ([RFC-010](https://github.com/appwrite/rfc/blob/main/010-anonymous-login.md), #914)
- Added new Environment Variable to enable or disable Anonymous Login
- Added events for functions and executions (#971)
- Splited token & session models to become 2 different internal entities (#922)
- Added JWT support
- Added ARM support
- Splitted token & session models to become 2 different internal entities (#922)
- Added Dart 2.12 as a new Cloud Functions runtime (#989)
- Added option to disable email/password
- Added option to disable anonymous login (need to merge and apply changed)
- Added option to disable JWT auth
- Added option to disable team invites
- Option to limit number of users (good for app launches + god account PR)
- Added 2 new endpoints to the projects API to allow new settings
- Enabled 501 errors (Not Implemented) from the error handler
- Added Python 3.9 as a new Cloud Functions runtime
- Added Deno 1.8 as a new Cloud Functions runtime (#989)
- Upgraded to PHP 8.0 (#713)
- ClamAV is now disabled by default to allow lower min requirments for Appwrite (#1064)
- Added a new env var named `_APP_LOCALE` that allow to change the default `en` locale value (#1056)
- Updated all the console bottom control to be consistent. Dropped the `+` icon (#1062)
- Added Response Models for Documents and Preferences
## Bugs
- Fixed default value for HTTPS force option
- Fixed form array casting in dashboard
- Fixed collection document rule form in dashboard
## Breaking Changes
## Breaking Changes (Read before upgrading!)
- Rename `deleteuser` to `delete` on Users Api
- Environment variable `_APP_FUNCTIONS_ENVS` renamed to `_APP_FUNCTIONS_RUNTIMES`
- Only logged in users can execute functions (for guests, use anonymous login)
- Only the user who has triggered the execution get access to the relevant execution logs
- Function execution env `APPWRITE_FUNCTION_EVENT_PAYLOAD` renamed to `APPWRITE_FUNCTION_EVENT_DATA`
- Function execution environment variable `APPWRITE_FUNCTION_EVENT_PAYLOAD` renamed to `APPWRITE_FUNCTION_EVENT_DATA`
- Function execution environment variable `APPWRITE_FUNCTION_ENV_NAME` renamed to `APPWRITE_FUNCTION_RUNTIME_NAME`
- Function execution environment variable `APPWRITE_FUNCTION_ENV_VERSION` renamed to `APPWRITE_FUNCTION_RUNTIME_VERSION`
- Introdcues rate limits for:
- Team invite (10 requests in every 60 minutes per IP address)
# Version 0.7.2

View file

@ -280,13 +280,9 @@ Before running the command, make sure you have proper write permissions to the A
```bash
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -t appwrite/appwrite:dev --push .
```
**Build Functions Envs**
**Build Functions Runtimes**
Build envs for all supported cloud functions (multicore builds)
```bash
bash ./docker/environments/build.sh
```
The Runtimes for all supported cloud functions (multicore builds) can be found at the [appwrite/php-runtimes](https://github.com/appwrite/php-runtimes) repository.
## Tests

View file

@ -12,12 +12,13 @@ RUN composer update --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM php:7.4-cli-alpine as step1
FROM php:8.0-cli-alpine as step1
ENV PHP_REDIS_VERSION=5.3.3 \
PHP_SWOOLE_VERSION=v4.5.8 \
PHP_MAXMINDDB_VERSION=v1.10.0 \
PHP_XDEBUG_VERSION=sdebug_2_9-beta
ENV PHP_REDIS_VERSION=5.3.4 \
PHP_SWOOLE_VERSION=v4.6.6 \
PHP_IMAGICK_VERSION=master \
PHP_YAML_VERSION=2.2.1 \
PHP_MAXMINDDB_VERSION=v1.10.1
RUN \
apk add --no-cache --virtual .deps \
@ -29,39 +30,53 @@ RUN \
git \
zlib-dev \
brotli-dev \
libmaxminddb-dev \
openssl-dev
openssl-dev \
yaml-dev \
imagemagick \
imagemagick-dev \
libmaxminddb-dev
RUN docker-php-ext-install sockets
RUN \
# Redis Extension
git clone https://github.com/phpredis/phpredis.git && \
git clone --depth 1 --branch $PHP_REDIS_VERSION https://github.com/phpredis/phpredis.git && \
cd phpredis && \
git checkout $PHP_REDIS_VERSION && \
phpize && \
./configure && \
make && make install && \
cd .. && \
## Swoole Extension
git clone https://github.com/swoole/swoole-src.git && \
git clone --depth 1 --branch $PHP_SWOOLE_VERSION https://github.com/swoole/swoole-src.git && \
cd swoole-src && \
git checkout $PHP_SWOOLE_VERSION && \
phpize && \
./configure --enable-sockets --enable-http2 --enable-openssl && \
make && make install && \
cd .. && \
## Imagick Extension
git clone --depth 1 --branch $PHP_IMAGICK_VERSION https://github.com/Imagick/imagick && \
cd imagick && \
phpize && \
./configure && \
make && make install && \
cd .. && \
## YAML Extension
git clone --depth 1 --branch $PHP_YAML_VERSION https://github.com/php/pecl-file_formats-yaml && \
cd pecl-file_formats-yaml && \
phpize && \
./configure && \
make && make install && \
cd .. && \
## Maxminddb extension
git clone https://github.com/maxmind/MaxMind-DB-Reader-php.git && \
git clone --depth 1 --branch $PHP_MAXMINDDB_VERSION https://github.com/maxmind/MaxMind-DB-Reader-php.git && \
cd MaxMind-DB-Reader-php && \
git checkout $PHP_MAXMINDDB_VERSION && \
cd ext && \
phpize && \
./configure && \
make && make install && \
cd ../..
FROM php:7.4-cli-alpine as final
FROM php:8.0-cli-alpine as final
LABEL maintainer="team@appwrite.io"
@ -125,16 +140,14 @@ RUN \
curl-dev \
&& apk add --no-cache \
libstdc++ \
certbot \
brotli-dev \
yaml-dev \
imagemagick \
imagemagick-dev \
libmaxminddb-dev \
certbot \
docker-cli \
docker-compose \
libmaxminddb \
libmaxminddb-dev \
&& pecl install imagick yaml \
&& docker-php-ext-enable imagick yaml \
&& docker-php-ext-install sockets opcache pdo_mysql \
&& apk del .deps \
&& rm -rf /var/cache/apk/*
@ -142,9 +155,11 @@ RUN \
WORKDIR /usr/src/code
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/maxminddb.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/imagick.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/yaml.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/maxminddb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
# Add Source Code
COPY ./app /usr/src/code/app
@ -193,12 +208,16 @@ RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini
RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini
RUN echo extension=imagick.so >> /usr/local/etc/php/conf.d/imagick.ini
RUN echo extension=yaml.so >> /usr/local/etc/php/conf.d/yaml.ini
RUN echo extension=maxminddb.so >> /usr/local/etc/php/conf.d/maxminddb.ini
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "default_socket_timeout=-1" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.jit_buffer_size=100M" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.jit=1235" >> /usr/local/etc/php/conf.d/appwrite.ini
EXPOSE 80

42
app/config/auth.php Normal file
View file

@ -0,0 +1,42 @@
<?php
// Auth methods
return [
'email-password' => [
'name' => 'Email/Password',
'key' => 'usersAuthEmailPassword',
'icon' => '/images/users/email-password.png',
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateSession',
'enabled' => true,
],
'anonymous' => [
'name' => 'Anonymous',
'key' => 'usersAuthAnonymous',
'icon' => '/images/users/anonymous.png',
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateAnonymousSession',
'enabled' => true,
],
'invites' => [
'name' => 'Invites',
'key' => 'usersAuthInvites',
'icon' => '/images/users/invites.png',
'docs' => 'https://appwrite.io/docs/client/teams?sdk=web#teamsCreateMembership',
'enabled' => true,
],
'jwt' => [
'name' => 'JWT',
'key' => 'usersAuthJWT',
'icon' => '/images/users/jwt.png',
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateJWT',
'enabled' => true,
],
'phone' => [
'name' => 'Phone',
'key' => 'usersAuthPhone',
'icon' => '/images/users/phone.png',
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreatePhoneSession',
'docs' => '',
'enabled' => false,
],
];

View file

@ -5,6 +5,7 @@ use Utopia\Config\Config;
use Appwrite\Database\Database;
$providers = Config::getParam('providers', []);
$auth = Config::getParam('auth', []);
$collections = [
'console' => [
@ -770,6 +771,14 @@ $collections = [
'default' => '',
'required' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Max users allowed',
'key' => 'usersAuthLimit',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => 0,
'required' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Webhooks',
@ -1710,4 +1719,15 @@ foreach ($providers as $index => $provider) {
];
}
foreach ($auth as $index => $method) {
$collections[Database::SYSTEM_COLLECTION_PROJECTS]['rules'][] = [
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => $method['name'] || '',
'key' => $method['key'] || '',
'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN,
'default' => true,
'required' => false,
];
}
return $collections;

View file

@ -1,156 +0,0 @@
<?php
use Utopia\App;
use Utopia\System\System;
/**
* List of Appwrite Cloud Functions supported environments
*/
$environments = [
'node-14.5' => [
'name' => 'Node.js',
'version' => '14.5',
'base' => 'node:14.5-alpine',
'image' => 'appwrite/env-node-14.5:1.0.0',
'build' => '/usr/src/code/docker/environments/node-14.5',
'logo' => 'node.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'node-15.5' => [
'name' => 'Node.js',
'version' => '15.5',
'base' => 'node:15.5-alpine',
'image' => 'appwrite/env-node-15.5:1.0.0',
'build' => '/usr/src/code/docker/environments/node-15.5',
'logo' => 'node.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'php-7.4' => [
'name' => 'PHP',
'version' => '7.4',
'base' => 'php:7.4-cli-alpine',
'image' => 'appwrite/env-php-7.4:1.0.0',
'build' => '/usr/src/code/docker/environments/php-7.4',
'logo' => 'php.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'php-8.0' => [
'name' => 'PHP',
'version' => '8.0',
'base' => 'php:8.0-cli-alpine',
'image' => 'appwrite/env-php-8.0:1.0.0',
'build' => '/usr/src/code/docker/environments/php-8.0',
'logo' => 'php.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'ruby-2.7' => [
'name' => 'Ruby',
'version' => '2.7',
'base' => 'ruby:2.7-alpine',
'image' => 'appwrite/env-ruby-2.7:1.0.2',
'build' => '/usr/src/code/docker/environments/ruby-2.7',
'logo' => 'ruby.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'ruby-3.0' => [
'name' => 'Ruby',
'version' => '3.0',
'base' => 'ruby:3.0-alpine',
'image' => 'appwrite/env-ruby-3.0:1.0.0',
'build' => '/usr/src/code/docker/environments/ruby-3.0',
'logo' => 'ruby.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'python-3.8' => [
'name' => 'Python',
'version' => '3.8',
'base' => 'python:3.8-alpine',
'image' => 'appwrite/env-python-3.8:1.0.0',
'build' => '/usr/src/code/docker/environments/python-3.8',
'logo' => 'python.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'python-3.9' => [
'name' => 'Python',
'version' => '3.9',
'base' => 'python:3.9-alpine',
'image' => 'appwrite/env-python-3.9:1.0.0',
'build' => '/usr/src/code/docker/environments/python-3.9',
'logo' => 'python.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'deno-1.2' => [
'name' => 'Deno',
'version' => '1.2',
'base' => 'hayd/deno:alpine-1.2.0',
'image' => 'appwrite/env-deno-1.2:1.0.0',
'build' => '/usr/src/code/docker/environments/deno-1.2',
'logo' => 'deno.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'deno-1.5' => [
'name' => 'Deno',
'version' => '1.5',
'base' => 'hayd/deno:alpine-1.5.0',
'image' => 'appwrite/env-deno-1.5:1.0.0',
'build' => '/usr/src/code/docker/environments/deno-1.5',
'logo' => 'deno.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'deno-1.6' => [
'name' => 'Deno',
'version' => '1.6',
'base' => 'hayd/deno:alpine-1.6.0',
'image' => 'appwrite/env-deno-1.6:1.0.0',
'build' => '/usr/src/code/docker/environments/deno-1.6',
'logo' => 'deno.png',
'supports' => [System::X86, System::PPC, System::ARM],
],
'dart-2.10' => [
'name' => 'Dart',
'version' => '2.10',
'base' => 'google/dart:2.10',
'image' => 'appwrite/env-dart-2.10:1.0.0',
'build' => '/usr/src/code/docker/environments/dart-2.10',
'logo' => 'dart.png',
'supports' => [System::X86],
],
'dart-2.12' => [
'name' => 'Dart',
'version' => '2.12',
'base' => 'google/dart:2.12',
'image' => 'appwrite/env-dart-2.12:1.0.0',
'build' => '/usr/src/code/docker/environments/dart-2.12',
'logo' => 'dart.png',
'supports' => [System::X86],
],
'dotnet-3.1' => [
'name' => '.NET',
'version' => '3.1',
'base' => 'mcr.microsoft.com/dotnet/runtime:3.1-alpine',
'image' => 'appwrite/env-dotnet-3.1:1.0.0',
'build' => '/usr/src/code/docker/environments/dotnet-3.1',
'logo' => 'dotnet.png',
'supports' => [System::X86, System::ARM],
],
'dotnet-5.0' => [
'name' => '.NET',
'version' => '5.0',
'base' => 'mcr.microsoft.com/dotnet/runtime:5.0-alpine',
'image' => 'appwrite/env-dotnet-5.0:1.0.0',
'build' => '/usr/src/code/docker/environments/dotnet-5.0',
'logo' => 'dotnet.png',
'supports' => [System::X86, System::ARM],
],
];
$allowList = empty(App::getEnv('_APP_FUNCTIONS_ENVS', null)) ? false : \explode(',', App::getEnv('_APP_FUNCTIONS_ENVS', null));
$environments = array_filter($environments, function ($environment, $key) use ($allowList) {
$isAllowed = $allowList && in_array($key, $allowList);
$isSupported = in_array(System::getArchEnum(), $environment["supports"]);
return $allowList ? ($isAllowed && $isSupported) : $isSupported;
}, ARRAY_FILTER_USE_BOTH);
return $environments;

View file

@ -84,17 +84,17 @@ return [
],
'database.documents.create' => [
'description' => 'This event triggers when a database document is created.',
'model' => Response::MODEL_ANY,
'model' => Response::MODEL_DOCUMENT,
'note' => '',
],
'database.documents.update' => [
'description' => 'This event triggers when a database document is updated.',
'model' => Response::MODEL_ANY,
'model' => Response::MODEL_DOCUMENT,
'note' => '',
],
'database.documents.delete' => [
'description' => 'This event triggers when a database document is deleted.',
'model' => Response::MODEL_ANY,
'model' => Response::MODEL_DOCUMENT,
'note' => '',
],
'functions.create' => [

View file

@ -6,6 +6,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.amazon.com/apps-and-games/services-and-apis',
'icon' => 'icon-amazon',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -15,6 +16,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.apple.com/',
'icon' => 'icon-apple',
'enabled' => true,
'sandbox' => false,
'form' => 'apple.phtml', // Perperation for adding ability to customized OAuth UI forms, currently handled hardcoded.
'beta' => true,
'mock' => false,
@ -24,6 +26,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.atlassian.com/bitbucket',
'icon' => 'icon-bitbucket',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -33,6 +36,7 @@ return [ // Ordered by ABC.
'developers' => 'https://dev.bitly.com/v4_documentation.html',
'icon' => 'icon-bitly',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false
@ -42,6 +46,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.box.com/reference/',
'icon' => 'icon-box',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false
@ -51,6 +56,7 @@ return [ // Ordered by ABC.
'developers' => 'https://discordapp.com/developers/docs/topics/oauth2',
'icon' => 'icon-discord',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -60,6 +66,7 @@ return [ // Ordered by ABC.
'developers' => 'https://www.dropbox.com/developers/documentation',
'icon' => 'icon-dropbox',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -69,6 +76,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developers.facebook.com/',
'icon' => 'icon-facebook',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -78,6 +86,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.github.com/',
'icon' => 'icon-github-circled',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -87,6 +96,7 @@ return [ // Ordered by ABC.
'developers' => 'https://docs.gitlab.com/ee/api/',
'icon' => 'icon-gitlab',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -96,6 +106,7 @@ return [ // Ordered by ABC.
'developers' => 'https://support.google.com/googleapi/answer/6158849',
'icon' => 'icon-google',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -105,6 +116,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.linkedin.com/',
'icon' => 'icon-linkedin',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -114,6 +126,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.microsoft.com/en-us/',
'icon' => 'icon-windows',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -123,15 +136,17 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.paypal.com/docs/api/overview/',
'icon' => 'icon-paypal',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false
],
'paypalSandbox' => [
'name' => 'PayPal (Sandbox)',
'name' => 'PayPal',
'developers' => 'https://developer.paypal.com/docs/api/overview/',
'icon' => 'icon-paypal',
'enabled' => true,
'sandbox' => true,
'form' => false,
'beta' => false,
'mock' => false
@ -141,6 +156,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.salesforce.com/docs/',
'icon' => 'icon-salesforce',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -150,6 +166,7 @@ return [ // Ordered by ABC.
'developers' => 'https://api.slack.com/',
'icon' => 'icon-slack',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -159,6 +176,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.spotify.com/documentation/general/guides/authorization-guide/',
'icon' => 'icon-spotify',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -168,15 +186,17 @@ return [ // Ordered by ABC.
'developers' => 'https://developers.tradeshift.com/docs/api',
'icon' => 'icon-tradeshift',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
],
'tradeshiftBox' => [
'name' => 'Tradeshift Sandbox',
'name' => 'Tradeshift',
'developers' => 'https://developers.tradeshift.com/docs/api',
'icon' => 'icon-tradeshiftbox',
'enabled' => true,
'sandbox' => true,
'form' => false,
'beta' => false,
'mock' => false,
@ -186,6 +206,7 @@ return [ // Ordered by ABC.
'developers' => 'https://dev.twitch.tv/docs/authentication',
'icon' => 'icon-twitch',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -195,6 +216,7 @@ return [ // Ordered by ABC.
'developers' => 'https://vk.com/dev',
'icon' => 'icon-vk',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -204,6 +226,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.yahoo.com/oauth2/guide/flows_authcode/',
'icon' => 'icon-yahoo',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -213,6 +236,7 @@ return [ // Ordered by ABC.
'developers' => 'https://tech.yandex.com/oauth/',
'icon' => 'icon-yandex',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
@ -238,6 +262,7 @@ return [ // Ordered by ABC.
'developers' => 'https://developer.wordpress.com/docs/oauth2/',
'icon' => 'icon-wordpress',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false
@ -248,6 +273,7 @@ return [ // Ordered by ABC.
'developers' => 'https://appwrite.io',
'icon' => 'icon-appwrite',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => true,

15
app/config/runtimes.php Normal file
View file

@ -0,0 +1,15 @@
<?php
use Utopia\App;
use Appwrite\Runtimes\Runtimes;
/**
* List of Appwrite Cloud Functions supported runtimes
*/
$runtimes = new Runtimes();
$allowList = empty(App::getEnv('_APP_FUNCTIONS_RUNTIMES')) ? [] : \explode(',', App::getEnv('_APP_FUNCTIONS_RUNTIMES'));
$runtimes = $runtimes->getAll(filter: $allowList);
return $runtimes;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -33,7 +33,7 @@ return [
],
[
'name' => '_APP_OPTIONS_FORCE_HTTPS',
'description' => 'Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'disabled\'. To enable, set to \'enabled\'. This feature will work only when your ports are set to default 80 and 443.',
'description' => 'Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443.',
'introduction' => '',
'default' => 'disabled',
'required' => false,
@ -386,10 +386,18 @@ return [
'question' => '',
],
[
'name' => '_APP_FUNCTIONS_ENVS',
'name' => '_APP_FUNCTIONS_RUNTIMES',
'description' => 'This option allows you to limit the available environments for cloud functions. This option is very useful for low-cost servers to safe disk space.\n\nTo enable/activate this option, pass a list of allowed environments separated by a comma.\n\nCurrently, supported environments are: ' . \implode(', ', \array_keys(Config::getParam('providers'))),
'introduction' => '0.8.0',
'default' => 'node-15.5,deno-1.8,php-8.0,python-3.9,ruby-3.0,dotnet-5.0',
'required' => false,
'question' => '',
],
[
'name' => '_APP_FUNCTIONS_ENVS',
'description' => 'Deprectated with 0.8.0, use \'_APP_FUNCTIONS_RUNTIMES\' instead!',
'introduction' => '0.7.0',
'default' => 'node-14.5,deno-1.6,php-7.4,python-3.9,ruby-3.0,dotnet-5.0',
'default' => 'node-14.5,deno-1.8,php-7.4,python-3.9,ruby-3.0,dotnet-5.0',
'required' => false,
'question' => '',
],

View file

@ -31,10 +31,11 @@ $oauthDefaultFailure = App::getEnv('_APP_HOME').'/auth/oauth2/failure';
App::post('/v1/account')
->desc('Create Account')
->groups(['api', 'account'])
->groups(['api', 'account', 'auth'])
->label('event', 'account.create')
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('auth.type', 'emailPassword')
->label('sdk.auth', [])
->label('sdk.namespace', 'account')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/account/create.md')
@ -75,6 +76,22 @@ App::post('/v1/account')
}
}
$limit = $project->getAttribute('usersAuthLimit', 0);
if ($limit !== 0) {
$projectDB->getCollection([ // Count users
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$sum = $projectDB->getSum();
if($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
}
}
$profile = $projectDB->getCollectionFirst([ // Get user by email address
'limit' => 1,
'filters' => [
@ -133,10 +150,11 @@ App::post('/v1/account')
App::post('/v1/account/sessions')
->desc('Create Account Session')
->groups(['api', 'account'])
->groups(['api', 'account', 'auth'])
->label('event', 'account.sessions.create')
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('auth.type', 'emailPassword')
->label('sdk.auth', [])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createSession')
->label('sdk.description', '/docs/references/account/create-session.md')
@ -252,7 +270,7 @@ App::get('/v1/account/sessions/oauth2/:provider')
->groups(['api', 'account'])
->label('error', __DIR__.'/../../views/general/error.phtml')
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createOAuth2Session')
->label('sdk.description', '/docs/references/account/create-session-oauth2.md')
@ -469,7 +487,23 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
],
]);
if (!$user || empty($user->getId())) { // Last option -> create user alone, generate random password
if (!$user || empty($user->getId())) { // Last option -> create the user, generate random password
$limit = $project->getAttribute('usersAuthLimit', 0);
if ($limit !== 0) {
$projectDB->getCollection([ // Count users
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$sum = $projectDB->getSum();
if($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
}
}
Authorization::disable();
try {
@ -579,10 +613,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
App::post('/v1/account/sessions/anonymous')
->desc('Create Anonymous Session')
->groups(['api', 'account'])
->groups(['api', 'account', 'auth'])
->label('event', 'account.sessions.create')
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('auth.type', 'anonymous')
->label('sdk.auth', [])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createAnonymousSession')
->label('sdk.description', '/docs/references/account/create-session-anonymous.md')
@ -611,10 +646,30 @@ App::post('/v1/account/sessions/anonymous')
$protocol = $request->getProtocol();
if ($user->getId() || 'console' === $project->getId()) {
if ('console' === $project->getId()) {
throw new Exception('Failed to create anonymous user.', 401);
}
if ($user->getId()) {
throw new Exception('Cannot create an anonymous user when logged in.', 401);
}
$limit = $project->getAttribute('usersAuthLimit', 0);
if ($limit !== 0) {
$projectDB->getCollection([ // Count users
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$sum = $projectDB->getSum();
if($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
}
}
Authorization::disable();
try {
$user = $projectDB->createDocument([
@ -635,7 +690,6 @@ App::post('/v1/account/sessions/anonymous')
} catch (Exception $th) {
throw new Exception('Failed saving user to DB', 500);
}
Authorization::reset();
if (false === $user) {
@ -703,10 +757,10 @@ App::post('/v1/account/sessions/anonymous')
App::post('/v1/account/jwt')
->desc('Create Account JWT')
->groups(['api', 'account'])
->groups(['api', 'account', 'auth'])
->label('scope', 'account')
->label('docs', false) // Hidden for now - private beta
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('auth.type', 'jwt')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createJWT')
->label('sdk.description', '/docs/references/account/create-jwt.md')
@ -751,7 +805,7 @@ App::get('/v1/account')
->desc('Get Account')
->groups(['api', 'account'])
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/account/get.md')
@ -771,13 +825,13 @@ App::get('/v1/account/prefs')
->desc('Get Account Preferences')
->groups(['api', 'account'])
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/account/get-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->inject('response')
->inject('user')
->action(function ($response, $user) {
@ -786,14 +840,14 @@ App::get('/v1/account/prefs')
$prefs = $user->getAttribute('prefs', new \stdClass());
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::get('/v1/account/sessions')
->desc('Get Account Sessions')
->groups(['api', 'account'])
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'getSessions')
->label('sdk.description', '/docs/references/account/get-sessions.md')
@ -833,7 +887,7 @@ App::get('/v1/account/logs')
->desc('Get Account Logs')
->groups(['api', 'account'])
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'getLogs')
->label('sdk.description', '/docs/references/account/get-logs.md')
@ -910,7 +964,7 @@ App::patch('/v1/account/name')
->groups(['api', 'account'])
->label('event', 'account.update.name')
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateName')
->label('sdk.description', '/docs/references/account/update-name.md')
@ -950,7 +1004,7 @@ App::patch('/v1/account/password')
->groups(['api', 'account'])
->label('event', 'account.update.password')
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updatePassword')
->label('sdk.description', '/docs/references/account/update-password.md')
@ -995,7 +1049,7 @@ App::patch('/v1/account/email')
->groups(['api', 'account'])
->label('event', 'account.update.email')
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateEmail')
->label('sdk.description', '/docs/references/account/update-email.md')
@ -1064,13 +1118,13 @@ App::patch('/v1/account/prefs')
->groups(['api', 'account'])
->label('event', 'account.update.prefs')
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/account/update-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_USER)
->param('prefs', [], new Assoc(), 'Prefs key-value JSON object.')
->inject('response')
->inject('user')
@ -1103,7 +1157,7 @@ App::delete('/v1/account')
->groups(['api', 'account'])
->label('event', 'account.delete')
->label('scope', 'account')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/account/delete.md')
@ -1169,7 +1223,7 @@ App::delete('/v1/account/sessions/:sessionId')
->groups(['api', 'account'])
->label('scope', 'account')
->label('event', 'account.sessions.delete')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'deleteSession')
->label('sdk.description', '/docs/references/account/delete-session.md')
@ -1245,7 +1299,7 @@ App::delete('/v1/account/sessions')
->groups(['api', 'account'])
->label('scope', 'account')
->label('event', 'account.sessions.delete')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'deleteSessions')
->label('sdk.description', '/docs/references/account/delete-sessions.md')
@ -1314,7 +1368,7 @@ App::post('/v1/account/recovery')
->groups(['api', 'account'])
->label('scope', 'public')
->label('event', 'account.recovery.create')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createRecovery')
->label('sdk.description', '/docs/references/account/create-recovery.md')
@ -1343,7 +1397,7 @@ App::post('/v1/account/recovery')
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $events */
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
$profile = $projectDB->getCollectionFirst([ // Get user by email address
@ -1433,7 +1487,7 @@ App::post('/v1/account/recovery')
$recovery // Hide secret for clients, sp
->setAttribute('secret',
($isPreviliggedUser || $isAppUser) ? $secret : '');
($isPrivilegedUser || $isAppUser) ? $secret : '');
$audits
->setParam('userId', $profile->getId())
@ -1452,7 +1506,7 @@ App::put('/v1/account/recovery')
->groups(['api', 'account'])
->label('scope', 'public')
->label('event', 'account.recovery.update')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateRecovery')
->label('sdk.description', '/docs/references/account/update-recovery.md')
@ -1531,7 +1585,7 @@ App::post('/v1/account/verification')
->groups(['api', 'account'])
->label('scope', 'account')
->label('event', 'account.verification.create')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createVerification')
->label('sdk.description', '/docs/references/account/create-verification.md')
@ -1561,7 +1615,7 @@ App::post('/v1/account/verification')
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\Event $mails */
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
$verificationSecret = Auth::tokenGenerator();
@ -1636,7 +1690,7 @@ App::post('/v1/account/verification')
$verification // Hide secret for clients, sp
->setAttribute('secret',
($isPreviliggedUser || $isAppUser) ? $verificationSecret : '');
($isPrivilegedUser || $isAppUser) ? $verificationSecret : '');
$audits
->setParam('userId', $user->getId())
@ -1655,7 +1709,7 @@ App::put('/v1/account/verification')
->groups(['api', 'account'])
->label('scope', 'public')
->label('event', 'account.verification.update')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateVerification')
->label('sdk.description', '/docs/references/account/update-verification.md')

View file

@ -38,7 +38,7 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response)
$output = 'png';
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT'; // 45 days cache
$key = \md5('/v1/avatars/:type/:code-' . $code . $width . $height . $quality . $output);
$key = \md5('/v1/avatars/'.$type.'/:code-' . $code . $width . $height . $quality . $output);
$path = $set[$code];
$type = 'png';
@ -83,7 +83,7 @@ App::get('/v1/avatars/credit-cards/:code')
->desc('Get Credit Card Icon')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getCreditCard')
->label('sdk.methodType', 'location')
@ -103,7 +103,7 @@ App::get('/v1/avatars/browsers/:code')
->desc('Get Browser Icon')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getBrowser')
->label('sdk.methodType', 'location')
@ -123,7 +123,7 @@ App::get('/v1/avatars/flags/:code')
->desc('Get Country Flag')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getFlag')
->label('sdk.methodType', 'location')
@ -143,7 +143,7 @@ App::get('/v1/avatars/image')
->desc('Get Image from URL')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getImage')
->label('sdk.methodType', 'location')
@ -212,7 +212,7 @@ App::get('/v1/avatars/favicon')
->desc('Get Favicon')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getFavicon')
->label('sdk.methodType', 'location')
@ -365,7 +365,7 @@ App::get('/v1/avatars/qr')
->desc('Get QR Code')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getQR')
->label('sdk.methodType', 'location')
@ -408,7 +408,7 @@ App::get('/v1/avatars/initials')
->desc('Get User Initials')
->groups(['api', 'avatars'])
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getInitials')
->label('sdk.methodType', 'location')

View file

@ -24,7 +24,7 @@ App::post('/v1/database/collections')
->label('event', 'database.collections.create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.method', 'createCollection')
->label('sdk.description', '/docs/references/database/create-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -96,7 +96,7 @@ App::get('/v1/database/collections')
->groups(['api', 'database'])
->label('scope', 'collections.read')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.method', 'listCollections')
->label('sdk.description', '/docs/references/database/list-collections.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -133,7 +133,7 @@ App::get('/v1/database/collections/:collectionId')
->groups(['api', 'database'])
->label('scope', 'collections.read')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.method', 'getCollection')
->label('sdk.description', '/docs/references/database/get-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -161,7 +161,7 @@ App::put('/v1/database/collections/:collectionId')
->label('scope', 'collections.write')
->label('event', 'database.collections.update')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.method', 'updateCollection')
->label('sdk.description', '/docs/references/database/update-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -238,7 +238,7 @@ App::delete('/v1/database/collections/:collectionId')
->label('scope', 'collections.write')
->label('event', 'database.collections.delete')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.method', 'deleteCollection')
->label('sdk.description', '/docs/references/database/delete-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -289,12 +289,12 @@ App::post('/v1/database/collections/:collectionId/documents')
->label('event', 'database.documents.create')
->label('scope', 'documents.write')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.method', 'createDocument')
->label('sdk.description', '/docs/references/database/create-document.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_DOCUMENT)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('data', [], new JSON(), 'Document data as JSON object.')
->param('read', 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)
@ -401,7 +401,7 @@ App::post('/v1/database/collections/:collectionId/documents')
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($data, Response::MODEL_ANY)
->dynamic($data, Response::MODEL_DOCUMENT)
;
});
@ -410,7 +410,7 @@ App::get('/v1/database/collections/:collectionId/documents')
->groups(['api', 'database'])
->label('scope', 'documents.read')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.method', 'listDocuments')
->label('sdk.description', '/docs/references/database/list-documents.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -473,12 +473,12 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
->groups(['api', 'database'])
->label('scope', 'documents.read')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.method', 'getDocument')
->label('sdk.description', '/docs/references/database/get-document.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_DOCUMENT)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->inject('response')
@ -494,7 +494,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
throw new Exception('No document found', 404);
}
$response->dynamic($document, Response::MODEL_ANY);
$response->dynamic($document, Response::MODEL_DOCUMENT);
});
App::patch('/v1/database/collections/:collectionId/documents/:documentId')
@ -503,12 +503,12 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->label('event', 'database.documents.update')
->label('scope', 'documents.write')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.method', 'updateDocument')
->label('sdk.description', '/docs/references/database/update-document.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_DOCUMENT)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->param('data', [], new JSON(), 'Document data as JSON object.')
@ -566,7 +566,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->setParam('data', $data->getArrayCopy())
;
$response->dynamic($data, Response::MODEL_ANY);
$response->dynamic($data, Response::MODEL_DOCUMENT);
});
App::delete('/v1/database/collections/:collectionId/documents/:documentId')
@ -575,7 +575,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
->label('scope', 'documents.write')
->label('event', 'database.documents.delete')
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.method', 'deleteDocument')
->label('sdk.description', '/docs/references/database/delete-document.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -614,9 +614,9 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
}
$events
->setParam('eventData', $response->output($document, Response::MODEL_ANY))
->setParam('eventData', $response->output($document, Response::MODEL_DOCUMENT))
;
$audits
->setParam('event', 'database.documents.delete')
->setParam('resource', 'database/document/'.$document->getId())

View file

@ -30,7 +30,7 @@ App::post('/v1/functions')
->desc('Create Function')
->label('scope', 'functions.write')
->label('event', 'functions.create')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/functions/create-function.md')
@ -39,7 +39,7 @@ App::post('/v1/functions')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->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('env', '', new WhiteList(array_keys(Config::getParam('environments')), true), 'Execution enviornment.')
->param('env', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution enviornment.')
->param('vars', [], new Assoc(), 'Key-value JSON object.', true)
->param('events', [], new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)), 'Events list.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
@ -83,7 +83,7 @@ App::get('/v1/functions')
->groups(['api', 'functions'])
->desc('List Functions')
->label('scope', 'functions.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/functions/list-functions.md')
@ -120,7 +120,7 @@ App::get('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Get Function')
->label('scope', 'functions.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/functions/get-function.md')
@ -147,7 +147,7 @@ App::get('/v1/functions/:functionId/usage')
->desc('Get Function Usage')
->groups(['api', 'functions'])
->label('scope', 'functions.read')
->label('sdk.platform', [APP_PLATFORM_CONSOLE])
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getUsage')
->param('functionId', '', new UID(), 'Function unique ID.')
@ -269,7 +269,7 @@ App::put('/v1/functions/:functionId')
->desc('Update Function')
->label('scope', 'functions.write')
->label('event', 'functions.update')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/functions/update-function.md')
@ -335,7 +335,7 @@ App::patch('/v1/functions/:functionId/tag')
->desc('Update Function Tag')
->label('scope', 'functions.write')
->label('event', 'functions.tags.update')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'updateTag')
->label('sdk.description', '/docs/references/functions/update-function-tag.md')
@ -393,7 +393,7 @@ App::delete('/v1/functions/:functionId')
->desc('Delete Function')
->label('scope', 'functions.write')
->label('event', 'functions.delete')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/functions/delete-function.md')
@ -431,7 +431,7 @@ App::post('/v1/functions/:functionId/tags')
->desc('Create Tag')
->label('scope', 'functions.write')
->label('event', 'functions.tags.create')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createTag')
->label('sdk.description', '/docs/references/functions/create-tag.md')
@ -525,7 +525,7 @@ App::get('/v1/functions/:functionId/tags')
->groups(['api', 'functions'])
->desc('List Tags')
->label('scope', 'functions.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listTags')
->label('sdk.description', '/docs/references/functions/list-tags.md')
@ -570,7 +570,7 @@ App::get('/v1/functions/:functionId/tags/:tagId')
->groups(['api', 'functions'])
->desc('Get Tag')
->label('scope', 'functions.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getTag')
->label('sdk.description', '/docs/references/functions/get-tag.md')
@ -609,7 +609,7 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
->desc('Delete Tag')
->label('scope', 'functions.write')
->label('event', 'functions.tags.delete')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'deleteTag')
->label('sdk.description', '/docs/references/functions/delete-tag.md')
@ -671,7 +671,7 @@ App::post('/v1/functions/:functionId/executions')
->desc('Create Execution')
->label('scope', 'execution.write')
->label('event', 'functions.executions.create')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createExecution')
->label('sdk.description', '/docs/references/functions/create-execution.md')
@ -784,7 +784,7 @@ App::get('/v1/functions/:functionId/executions')
->groups(['api', 'functions'])
->desc('List Executions')
->label('scope', 'execution.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listExecutions')
->label('sdk.description', '/docs/references/functions/list-executions.md')
@ -802,7 +802,9 @@ App::get('/v1/functions/:functionId/executions')
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
Authorization::disable();
$function = $projectDB->getDocument($functionId);
Authorization::reset();
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
throw new Exception('Function not found', 404);
@ -829,7 +831,7 @@ App::get('/v1/functions/:functionId/executions/:executionId')
->groups(['api', 'functions'])
->desc('Get Execution')
->label('scope', 'execution.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getExecution')
->label('sdk.description', '/docs/references/functions/get-execution.md')
@ -844,7 +846,9 @@ App::get('/v1/functions/:functionId/executions/:executionId')
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
Authorization::disable();
$function = $projectDB->getDocument($functionId);
Authorization::reset();
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
throw new Exception('Function not found', 404);

View file

@ -11,7 +11,7 @@ App::get('/v1/health')
->desc('Get HTTP')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/health/get.md')
@ -37,7 +37,7 @@ App::get('/v1/health/db')
->desc('Get DB')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getDB')
->label('sdk.description', '/docs/references/health/get-db.md')
@ -56,7 +56,7 @@ App::get('/v1/health/cache')
->desc('Get Cache')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getCache')
->label('sdk.description', '/docs/references/health/get-cache.md')
@ -74,7 +74,7 @@ App::get('/v1/health/time')
->desc('Get Time')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getTime')
->label('sdk.description', '/docs/references/health/get-time.md')
@ -123,7 +123,7 @@ App::get('/v1/health/queue/webhooks')
->desc('Get Webhooks Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueWebhooks')
->label('sdk.description', '/docs/references/health/get-queue-webhooks.md')
@ -138,7 +138,7 @@ App::get('/v1/health/queue/tasks')
->desc('Get Tasks Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueTasks')
->label('sdk.description', '/docs/references/health/get-queue-tasks.md')
@ -153,7 +153,7 @@ App::get('/v1/health/queue/logs')
->desc('Get Logs Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueLogs')
->label('sdk.description', '/docs/references/health/get-queue-logs.md')
@ -168,7 +168,7 @@ App::get('/v1/health/queue/usage')
->desc('Get Usage Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueUsage')
->label('sdk.description', '/docs/references/health/get-queue-usage.md')
@ -183,7 +183,7 @@ App::get('/v1/health/queue/certificates')
->desc('Get Certificate Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueCertificates')
->label('sdk.description', '/docs/references/health/get-queue-certificates.md')
@ -198,7 +198,7 @@ App::get('/v1/health/queue/functions')
->desc('Get Functions Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueFunctions')
->label('sdk.description', '/docs/references/health/get-queue-functions.md')
@ -213,7 +213,7 @@ App::get('/v1/health/storage/local')
->desc('Get Local Storage')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getStorageLocal')
->label('sdk.description', '/docs/references/health/get-storage-local.md')
@ -245,7 +245,7 @@ App::get('/v1/health/anti-virus')
->desc('Get Anti virus')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getAntiVirus')
->label('sdk.description', '/docs/references/health/get-storage-anti-virus.md')
@ -273,7 +273,7 @@ App::get('/v1/health/stats') // Currently only used internally
->desc('Get System Stats')
->groups(['api', 'health'])
->label('scope', 'god')
// ->label('sdk.platform', [APP_PLATFORM_SERVER])
// ->label('sdk.auth', [APP_AUTH_TYPE_KEY])
// ->label('sdk.namespace', 'health')
// ->label('sdk.method', 'getStats')
->label('docs', false)

View file

@ -9,7 +9,7 @@ App::get('/v1/locale')
->desc('Get User Locale')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/locale/get-locale.md')
@ -74,7 +74,7 @@ App::get('/v1/locale/countries')
->desc('List Countries')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCountries')
->label('sdk.description', '/docs/references/locale/get-countries.md')
@ -106,7 +106,7 @@ App::get('/v1/locale/countries/eu')
->desc('List EU Countries')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCountriesEU')
->label('sdk.description', '/docs/references/locale/get-countries-eu.md')
@ -141,7 +141,7 @@ App::get('/v1/locale/countries/phones')
->desc('List Countries Phone Codes')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCountriesPhones')
->label('sdk.description', '/docs/references/locale/get-countries-phones.md')
@ -177,7 +177,7 @@ App::get('/v1/locale/continents')
->desc('List Continents')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getContinents')
->label('sdk.description', '/docs/references/locale/get-continents.md')
@ -208,7 +208,7 @@ App::get('/v1/locale/currencies')
->desc('List Currencies')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCurrencies')
->label('sdk.description', '/docs/references/locale/get-currencies.md')
@ -233,7 +233,7 @@ App::get('/v1/locale/languages')
->desc('List Languages')
->groups(['api', 'locale'])
->label('scope', 'locale.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getLanguages')
->label('sdk.description', '/docs/references/locale/get-languages.md')

View file

@ -8,6 +8,7 @@ use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Appwrite\Network\Validator\URL;
use Utopia\Validator\Range;
use Utopia\Validator\Integer;
use Utopia\Config\Config;
use Utopia\Domains\Domain;
use Appwrite\Auth\Auth;
@ -24,6 +25,7 @@ App::post('/v1/projects')
->desc('Create Project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'create')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -96,6 +98,7 @@ App::get('/v1/projects')
->desc('List Projects')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'list')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -131,6 +134,7 @@ App::get('/v1/projects/:projectId')
->desc('Get Project')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'get')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -156,6 +160,7 @@ App::get('/v1/projects/:projectId/usage')
->desc('Get Project')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getUsage')
->param('projectId', '', new UID(), 'Project unique ID.')
@ -356,6 +361,7 @@ App::patch('/v1/projects/:projectId')
->desc('Update Project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'update')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -408,6 +414,7 @@ App::patch('/v1/projects/:projectId/oauth2')
->desc('Update Project OAuth2')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateOAuth2')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -441,10 +448,85 @@ App::patch('/v1/projects/:projectId/oauth2')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/limit')
->desc('Update Project users limit')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthLimit')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('limit', false, new Integer(true), 'Set the max number of users allowed in this project. Use 0 for unlimited.')
->inject('response')
->inject('consoleDB')
->action(function ($projectId, $limit, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
$project = $consoleDB->getDocument($projectId);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
if (false === $consoleDB->updateDocument(
\array_merge($project->getArrayCopy(), [
'usersAuthLimit' => $limit,
]))
) {
throw new Exception('Failed saving project to DB', 500);
};
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/:method')
->desc('Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthStatus')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: '.implode(',', \array_keys(Config::getParam('auth'))), false)
->param('status', false, new Boolean(true), 'Set the status of this auth method.')
->inject('response')
->inject('consoleDB')
->action(function ($projectId, $method, $status, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
$project = $consoleDB->getDocument($projectId);
$auth = Config::getParam('auth')[$method] ?? [];
$authKey = $auth['key'] ?? '';
$status = ($status === '1' || $status === 'true' || $status === 1 || $status === true);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
if (false === $consoleDB->updateDocument(
\array_merge($project->getArrayCopy(), [
$authKey => $status,
]))
) {
throw new Exception('Failed saving project to DB', 500);
};
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::delete('/v1/projects/:projectId')
->desc('Delete Project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'delete')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -510,6 +592,7 @@ App::post('/v1/projects/:projectId/webhooks')
->desc('Create Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createWebhook')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -572,6 +655,7 @@ App::get('/v1/projects/:projectId/webhooks')
->desc('List Webhooks')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listWebhooks')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -602,6 +686,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Get Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getWebhook')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -634,6 +719,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Update Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateWebhook')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -687,6 +773,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Delete Webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteWebhook')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -724,6 +811,7 @@ App::post('/v1/projects/:projectId/keys')
->desc('Create Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createKey')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -777,6 +865,7 @@ App::get('/v1/projects/:projectId/keys')
->desc('List Keys')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listKeys')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -807,6 +896,7 @@ App::get('/v1/projects/:projectId/keys/:keyId')
->desc('Get Key')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getKey')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -836,6 +926,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
->desc('Update Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateKey')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -879,6 +970,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
->desc('Delete Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteKey')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -916,6 +1008,7 @@ App::post('/v1/projects/:projectId/tasks')
->desc('Create Task')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createTask')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -996,6 +1089,7 @@ App::get('/v1/projects/:projectId/tasks')
->desc('List Tasks')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listTasks')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1027,6 +1121,7 @@ App::get('/v1/projects/:projectId/tasks/:taskId')
->desc('Get Task')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getTask')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1059,6 +1154,7 @@ App::put('/v1/projects/:projectId/tasks/:taskId')
->desc('Update Task')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateTask')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1127,6 +1223,7 @@ App::delete('/v1/projects/:projectId/tasks/:taskId')
->desc('Delete Task')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteTask')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -1164,6 +1261,7 @@ App::post('/v1/projects/:projectId/platforms')
->desc('Create Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createPlatform')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -1224,6 +1322,7 @@ App::get('/v1/projects/:projectId/platforms')
->desc('List Platforms')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listPlatforms')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1254,6 +1353,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
->desc('Get Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getPlatform')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1286,6 +1386,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
->desc('Update Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updatePlatform')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1334,6 +1435,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
->desc('Delete Platform')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deletePlatform')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -1371,6 +1473,7 @@ App::post('/v1/projects/:projectId/domains')
->desc('Create Domain')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createDomain')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -1440,6 +1543,7 @@ App::get('/v1/projects/:projectId/domains')
->desc('List Domains')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listDomains')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1470,6 +1574,7 @@ App::get('/v1/projects/:projectId/domains/:domainId')
->desc('Get Domain')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getDomain')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1502,6 +1607,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
->desc('Update Domain Verification Status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateDomainVerification')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -1565,6 +1671,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
->desc('Delete Domain')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteDomain')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)

View file

@ -28,7 +28,7 @@ App::post('/v1/storage/files')
->groups(['api', 'storage'])
->label('scope', 'files.write')
->label('event', 'storage.files.create')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'createFile')
->label('sdk.description', '/docs/references/storage/create-file.md')
@ -115,7 +115,7 @@ App::post('/v1/storage/files')
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
if (!$device->write($path, $data)) {
if (!$device->write($path, $data, $mimeType)) {
throw new Exception('Failed to save file', 500);
}
@ -167,7 +167,7 @@ App::get('/v1/storage/files')
->desc('List Files')
->groups(['api', 'storage'])
->label('scope', 'files.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'listFiles')
->label('sdk.description', '/docs/references/storage/list-files.md')
@ -204,7 +204,7 @@ App::get('/v1/storage/files/:fileId')
->desc('Get File')
->groups(['api', 'storage'])
->label('scope', 'files.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFile')
->label('sdk.description', '/docs/references/storage/get-file.md')
@ -231,7 +231,7 @@ App::get('/v1/storage/files/:fileId/preview')
->desc('Get File Preview')
->groups(['api', 'storage'])
->label('scope', 'files.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFilePreview')
->label('sdk.description', '/docs/references/storage/get-file-preview.md')
@ -242,13 +242,18 @@ App::get('/v1/storage/files/:fileId/preview')
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true)
->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true)
->param('borderRadius', 0, new Range(0, 4000), 'Preview image border radius in pixels. Pass an integer between 0 to 4000.', true)
->param('opacity', 1, new Range(0,1), 'Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.', true)
->param('rotation', 0, new Range(0,360), 'Preview image rotation in degrees. Pass an integer between 0 and 360.', true)
->param('background', '', new HexColor(), 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true)
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
->inject('request')
->inject('response')
->inject('project')
->inject('projectDB')
->action(function ($fileId, $width, $height, $quality, $background, $output, $request, $response, $project, $projectDB) {
->action(function ($fileId, $width, $height, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $projectDB) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
@ -273,7 +278,7 @@ App::get('/v1/storage/files/:fileId/preview')
$fileLogos = Config::getParam('storage-logos');
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = \md5($fileId.$width.$height.$quality.$background.$storage.$output);
$key = \md5($fileId.$width.$height.$quality.$borderWidth.$borderColor.$borderRadius.$opacity.$rotation.$background.$storage.$output);
$file = $projectDB->getDocument($fileId);
@ -293,7 +298,7 @@ App::get('/v1/storage/files/:fileId/preview')
$cipher = null;
$background = (empty($background)) ? 'eceff1' : $background;
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
$key = \md5($path.$width.$height.$quality.$background.$storage.$output);
$key = \md5($path.$width.$height.$quality.$borderWidth.$borderColor.$borderRadius.$opacity.$rotation.$background.$storage.$output);
}
$compressor = new GZIP();
@ -337,11 +342,28 @@ App::get('/v1/storage/files/:fileId/preview')
$image = new Image($source);
$image->crop((int) $width, (int) $height);
if (!empty($opacity) || $opacity==0) {
$image->setOpacity($opacity);
}
if (!empty($background)) {
$image->setBackground('#'.$background);
}
if (!empty($borderWidth) ) {
$image->setBorder($borderWidth, '#'.$borderColor);
}
if (!empty($borderRadius)) {
$image->setBorderRadius($borderRadius);
}
if (!empty($rotation)) {
$image->setRotation($rotation);
}
$output = (empty($output)) ? $type : $output;
$data = $image->output($output, $quality);
@ -362,7 +384,7 @@ App::get('/v1/storage/files/:fileId/download')
->desc('Get File for Download')
->groups(['api', 'storage'])
->label('scope', 'files.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileDownload')
->label('sdk.description', '/docs/references/storage/get-file-download.md')
@ -420,7 +442,7 @@ App::get('/v1/storage/files/:fileId/view')
->desc('Get File for View')
->groups(['api', 'storage'])
->label('scope', 'files.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileView')
->label('sdk.description', '/docs/references/storage/get-file-view.md')
@ -489,7 +511,7 @@ App::put('/v1/storage/files/:fileId')
->groups(['api', 'storage'])
->label('scope', 'files.write')
->label('event', 'storage.files.update')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'updateFile')
->label('sdk.description', '/docs/references/storage/update-file.md')
@ -538,7 +560,7 @@ App::delete('/v1/storage/files/:fileId')
->groups(['api', 'storage'])
->label('scope', 'files.write')
->label('event', 'storage.files.delete')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'deleteFile')
->label('sdk.description', '/docs/references/storage/delete-file.md')
@ -591,7 +613,7 @@ App::delete('/v1/storage/files/:fileId')
// ->desc('Scan Storage')
// ->groups(['api', 'storage'])
// ->label('scope', 'god')
// ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
// ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
// ->label('sdk.namespace', 'storage')
// ->label('sdk.method', 'getFileScan')
// ->label('sdk.hide', true)

View file

@ -25,7 +25,7 @@ App::post('/v1/teams')
->groups(['api', 'teams'])
->label('event', 'teams.create')
->label('scope', 'teams.write')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/teams/create-team.md')
@ -44,7 +44,7 @@ App::post('/v1/teams')
Authorization::disable();
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
$team = $projectDB->createDocument([
@ -54,7 +54,7 @@ App::post('/v1/teams')
'write' => ['team:{self}/owner'],
],
'name' => $name,
'sum' => ($isPreviliggedUser || $isAppUser) ? 0 : 1,
'sum' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'dateCreated' => \time(),
]);
@ -64,7 +64,7 @@ App::post('/v1/teams')
throw new Exception('Failed saving team to DB', 500);
}
if (!$isPreviliggedUser && !$isAppUser) { // Don't add user on server mode
if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode
$membership = new Document([
'$collection' => Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'$permissions' => [
@ -100,7 +100,7 @@ App::get('/v1/teams')
->desc('List Teams')
->groups(['api', 'teams'])
->label('scope', 'teams.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/teams/list-teams.md')
@ -137,7 +137,7 @@ App::get('/v1/teams/:teamId')
->desc('Get Team')
->groups(['api', 'teams'])
->label('scope', 'teams.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/teams/get-team.md')
@ -165,7 +165,7 @@ App::put('/v1/teams/:teamId')
->groups(['api', 'teams'])
->label('event', 'teams.update')
->label('scope', 'teams.write')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/teams/update-team.md')
@ -202,7 +202,7 @@ App::delete('/v1/teams/:teamId')
->groups(['api', 'teams'])
->label('event', 'teams.delete')
->label('scope', 'teams.write')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/teams/delete-team.md')
@ -251,16 +251,18 @@ App::delete('/v1/teams/:teamId')
App::post('/v1/teams/:teamId/memberships')
->desc('Create Team Membership')
->groups(['api', 'teams'])
->groups(['api', 'teams', 'auth'])
->label('event', 'teams.memberships.create')
->label('scope', 'teams.write')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('auth.type', 'invites')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'createMembership')
->label('sdk.description', '/docs/references/teams/create-team-membership.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
->label('abuse-limit', 10)
->param('teamId', '', new UID(), 'Team unique ID.')
->param('email', '', new Email(), 'New team member email.')
->param('name', '', new Text(128), 'New team member name. Max length: 128 chars.', true)
@ -281,7 +283,7 @@ App::post('/v1/teams/:teamId/memberships')
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $mails */
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
$name = (empty($name)) ? $email : $name;
@ -310,6 +312,22 @@ App::post('/v1/teams/:teamId/memberships')
if (empty($invitee)) { // Create new user if no user with same email found
$limit = $project->getAttribute('usersAuthLimit', 0);
if ($limit !== 0 && $project->getId() !== 'console') { // check users limit, console invites are allways allowed.
$projectDB->getCollection([ // Count users
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$sum = $projectDB->getSum();
if($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
}
}
Authorization::disable();
try {
@ -353,7 +371,7 @@ App::post('/v1/teams/:teamId/memberships')
}
}
if (!$isOwner && !$isPreviliggedUser && !$isAppUser) { // Not owner, not admin, not app (server)
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
throw new Exception('User is not allowed to send invitations for this team', 401);
}
@ -369,12 +387,12 @@ App::post('/v1/teams/:teamId/memberships')
'teamId' => $team->getId(),
'roles' => $roles,
'invited' => \time(),
'joined' => ($isPreviliggedUser || $isAppUser) ? \time() : 0,
'confirm' => ($isPreviliggedUser || $isAppUser),
'joined' => ($isPrivilegedUser || $isAppUser) ? \time() : 0,
'confirm' => ($isPrivilegedUser || $isAppUser),
'secret' => Auth::hash($secret),
]);
if ($isPreviliggedUser || $isAppUser) { // Allow admin to create membership
if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership
Authorization::disable();
$membership = $projectDB->createDocument($membership->getArrayCopy());
@ -426,7 +444,7 @@ App::post('/v1/teams/:teamId/memberships')
->setParam('{{text-cta}}', '#ffffff')
;
if (!$isPreviliggedUser && !$isAppUser) { // No need in comfirmation when in admin or app mode
if (!$isPrivilegedUser && !$isAppUser) { // No need in comfirmation when in admin or app mode
$mails
->setParam('event', 'teams.membership.create')
->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('account.emails.team'), $project->getAttribute('name')))
@ -457,7 +475,7 @@ App::get('/v1/teams/:teamId/memberships')
->desc('Get Team Memberships')
->groups(['api', 'teams'])
->label('scope', 'teams.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'getMemberships')
->label('sdk.description', '/docs/references/teams/get-team-members.md')
@ -511,7 +529,7 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status')
->groups(['api', 'teams'])
->label('event', 'teams.memberships.update.status')
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updateMembershipStatus')
->label('sdk.description', '/docs/references/teams/update-team-membership-status.md')
@ -658,7 +676,7 @@ App::delete('/v1/teams/:teamId/memberships/:inviteId')
->groups(['api', 'teams'])
->label('event', 'teams.memberships.delete')
->label('scope', 'teams.write')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'deleteMembership')
->label('sdk.description', '/docs/references/teams/delete-team-membership.md')

View file

@ -23,7 +23,7 @@ App::post('/v1/users')
->groups(['api', 'users'])
->label('event', 'users.create')
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/users/create-user.md')
@ -81,7 +81,7 @@ App::get('/v1/users')
->desc('List Users')
->groups(['api', 'users'])
->label('scope', 'users.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/users/list-users.md')
@ -118,7 +118,7 @@ App::get('/v1/users/:userId')
->desc('Get User')
->groups(['api', 'users'])
->label('scope', 'users.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/users/get-user.md')
@ -145,13 +145,13 @@ App::get('/v1/users/:userId/prefs')
->desc('Get User Preferences')
->groups(['api', 'users'])
->label('scope', 'users.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/users/get-user-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->param('userId', '', new UID(), 'User unique ID.')
->inject('response')
->inject('projectDB')
@ -167,14 +167,14 @@ App::get('/v1/users/:userId/prefs')
$prefs = $user->getAttribute('prefs', new \stdClass());
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::get('/v1/users/:userId/sessions')
->desc('Get User Sessions')
->groups(['api', 'users'])
->label('scope', 'users.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'getSessions')
->label('sdk.description', '/docs/references/users/get-user-sessions.md')
@ -220,7 +220,7 @@ App::get('/v1/users/:userId/logs')
->desc('Get User Logs')
->groups(['api', 'users'])
->label('scope', 'users.read')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'getLogs')
->label('sdk.description', '/docs/references/users/get-user-logs.md')
@ -335,7 +335,7 @@ App::patch('/v1/users/:userId/status')
->groups(['api', 'users'])
->label('event', 'users.update.status')
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'updateStatus')
->label('sdk.description', '/docs/references/users/update-user-status.md')
@ -372,13 +372,13 @@ App::patch('/v1/users/:userId/prefs')
->groups(['api', 'users'])
->label('event', 'users.update.prefs')
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/users/update-user-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->param('userId', '', new UID(), 'User unique ID.')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->inject('response')
@ -401,7 +401,7 @@ App::patch('/v1/users/:userId/prefs')
throw new Exception('Failed saving user to DB', 500);
}
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::delete('/v1/users/:userId/sessions/:sessionId')
@ -409,7 +409,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
->groups(['api', 'users'])
->label('event', 'users.sessions.delete')
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteSession')
->label('sdk.description', '/docs/references/users/delete-user-session.md')
@ -456,7 +456,7 @@ App::delete('/v1/users/:userId/sessions')
->groups(['api', 'users'])
->label('event', 'users.sessions.delete')
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteSessions')
->label('sdk.description', '/docs/references/users/delete-user-sessions.md')
@ -500,10 +500,10 @@ App::delete('/v1/users/:userId')
->groups(['api', 'users'])
->label('event', 'users.delete')
->label('scope', 'users.write')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteUser')
->label('sdk.description', '/docs/references/users/delete-user.md')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/users/delete.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
->param('userId', '', function () {return new UID();}, 'User unique ID.')

View file

@ -41,7 +41,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
$route = $utopia->match($request);
if (!empty($route->getLabel('sdk.platform', [])) && empty($project->getId()) && ($route->getLabel('scope', '') !== 'public')) {
if (!empty($route->getLabel('sdk.auth', [])) && empty($project->getId()) && ($route->getLabel('scope', '') !== 'public')) {
throw new Exception('Missing or unknown project ID', 400);
}
@ -271,7 +271,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
switch ($error->getCode()) {
switch ($error->getCode()) { // Don't show 500 errors!
case 400: // Error allowed publicly
case 401: // Error allowed publicly
case 402: // Error allowed publicly
@ -280,6 +280,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
case 409: // Error allowed publicly
case 412: // Error allowed publicly
case 429: // Error allowed publicly
case 501: // Error allowed publicly
$code = $error->getCode();
$message = $error->getMessage();
break;

View file

@ -15,7 +15,7 @@ App::get('/v1/mock/tests/foo')
->desc('Get Foo')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'foo')
->label('sdk.method', 'get')
->label('sdk.description', 'Mock a get request.')
@ -33,7 +33,7 @@ App::post('/v1/mock/tests/foo')
->desc('Post Foo')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'foo')
->label('sdk.method', 'post')
->label('sdk.description', 'Mock a post request.')
@ -51,7 +51,7 @@ App::patch('/v1/mock/tests/foo')
->desc('Patch Foo')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'foo')
->label('sdk.method', 'patch')
->label('sdk.description', 'Mock a patch request.')
@ -69,7 +69,7 @@ App::put('/v1/mock/tests/foo')
->desc('Put Foo')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'foo')
->label('sdk.method', 'put')
->label('sdk.description', 'Mock a put request.')
@ -87,7 +87,7 @@ App::delete('/v1/mock/tests/foo')
->desc('Delete Foo')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'foo')
->label('sdk.method', 'delete')
->label('sdk.description', 'Mock a delete request.')
@ -105,7 +105,7 @@ App::get('/v1/mock/tests/bar')
->desc('Get Bar')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'bar')
->label('sdk.method', 'get')
->label('sdk.description', 'Mock a get request.')
@ -123,7 +123,7 @@ App::post('/v1/mock/tests/bar')
->desc('Post Bar')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'bar')
->label('sdk.method', 'post')
->label('sdk.description', 'Mock a post request.')
@ -141,7 +141,7 @@ App::patch('/v1/mock/tests/bar')
->desc('Patch Bar')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'bar')
->label('sdk.method', 'patch')
->label('sdk.description', 'Mock a patch request.')
@ -159,7 +159,7 @@ App::put('/v1/mock/tests/bar')
->desc('Put Bar')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'bar')
->label('sdk.method', 'put')
->label('sdk.description', 'Mock a put request.')
@ -177,7 +177,7 @@ App::delete('/v1/mock/tests/bar')
->desc('Delete Bar')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'bar')
->label('sdk.method', 'delete')
->label('sdk.description', 'Mock a delete request.')
@ -195,7 +195,7 @@ App::post('/v1/mock/tests/general/upload')
->desc('Upload File')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'upload')
->label('sdk.description', 'Mock a file upload request.')
@ -240,7 +240,7 @@ App::get('/v1/mock/tests/general/redirect')
->desc('Redirect')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'redirect')
->label('sdk.description', 'Mock a redirect request.')
@ -258,7 +258,7 @@ App::get('/v1/mock/tests/general/redirect/done')
->desc('Redirected')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'redirected')
->label('sdk.description', 'Mock a redirected request.')
@ -273,7 +273,7 @@ App::get('/v1/mock/tests/general/set-cookie')
->desc('Set Cookie')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'setCookie')
->label('sdk.description', 'Mock a set cookie request.')
@ -292,7 +292,7 @@ App::get('/v1/mock/tests/general/get-cookie')
->desc('Get Cookie')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'getCookie')
->label('sdk.description', 'Mock a cookie response.')
@ -313,7 +313,7 @@ App::get('/v1/mock/tests/general/empty')
->desc('Empty Response')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'empty')
->label('sdk.description', 'Mock a an empty response.')
@ -331,7 +331,7 @@ App::get('/v1/mock/tests/general/400-error')
->desc('400 Error')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'error400')
->label('sdk.description', 'Mock a an 400 failed request.')
@ -347,7 +347,7 @@ App::get('/v1/mock/tests/general/500-error')
->desc('500 Error')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'error500')
->label('sdk.description', 'Mock a an 500 failed request.')
@ -370,7 +370,7 @@ App::get('/v1/mock/tests/general/oauth2')
->param('scope', '', new Text(100), 'OAuth2 scope list.')
->param('state', '', new Text(1024), 'OAuth2 state.')
->inject('response')
->action(function ($clientId, $redirectURI, $scope, $state, $response) {
->action(function ($client_id, $redirectURI, $scope, $state, $response) {
/** @var Appwrite\Utopia\Response $response */
$response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state]));
@ -387,14 +387,14 @@ App::get('/v1/mock/tests/general/oauth2/token')
->param('client_secret', '', new Text(100), 'OAuth2 scope list.')
->param('code', '', new Text(100), 'OAuth2 state.')
->inject('response')
->action(function ($clientId, $redirectURI, $clientSecret, $code, $response) {
->action(function ($client_id, $redirectURI, $client_secret, $code, $response) {
/** @var Appwrite\Utopia\Response $response */
if ($clientId != '1') {
if ($client_id != '1') {
throw new Exception('Invalid client ID');
}
if ($clientSecret != '123456') {
if ($client_secret != '123456') {
throw new Exception('Invalid client secret');
}

View file

@ -61,12 +61,12 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
;
}
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
if (($abuse->check() // Route is rate-limited
&& App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not diabled
&& (!$isAppUser && !$isPreviliggedUser)) // User is not an admin or API key
&& (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key
{
throw new Exception('Too many requests', 429);
}
@ -110,6 +110,60 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes'], 'api');
App::init(function ($utopia, $request, $response, $project, $user) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Document $user */
/** @var Utopia\Registry\Registry $register */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var Appwrite\Event\Event $functions */
$route = $utopia->match($request);
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
if($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
return;
}
switch ($route->getLabel('auth.type', '')) {
case 'emailPassword':
if($project->getAttribute('usersAuthEmailPassword', true) === false) {
throw new Exception('Email / Password authentication is disabled for this project', 501);
}
break;
case 'anonymous':
if($project->getAttribute('usersAuthAnonymous', true) === false) {
throw new Exception('Anonymous authentication is disabled for this project', 501);
}
break;
case 'invites':
if($project->getAttribute('usersAuthInvites', true) === false) {
throw new Exception('Invites authentication is disabled for this project', 501);
}
break;
case 'jwt':
if($project->getAttribute('usersAuthJWT', true) === false) {
throw new Exception('JWT authentication is disabled for this project', 501);
}
break;
default:
throw new Exception('Unsupported authentication route');
break;
}
}, ['utopia', 'request', 'response', 'project', 'user'], 'auth');
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $realtime, $mode) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */

View file

@ -32,7 +32,7 @@ App::init(function ($utopia, $request, $response, $layout) {
['type' => 'developer', 'label' => 'Developer'],
['type' => 'admin', 'label' => 'Admin'],
])
->setParam('environments', Config::getParam('environments'))
->setParam('runtimes', Config::getParam('runtimes'))
->setParam('mode', App::getMode())
;

View file

@ -323,7 +323,10 @@ App::get('/console/users')
$page = new View(__DIR__.'/../../views/console/users/index.phtml');
$page->setParam('providers', Config::getParam('providers'));
$page
->setParam('auth', Config::getParam('auth'))
->setParam('providers', Config::getParam('providers'))
;
$layout
->setParam('title', APP_NAME.' - Users')
@ -370,7 +373,7 @@ App::get('/console/functions')
$page = new View(__DIR__.'/../../views/console/functions/index.phtml');
$page
->setParam('environments', Config::getParam('environments'))
->setParam('runtimes', Config::getParam('runtimes'))
;
$layout

View file

@ -226,6 +226,12 @@ App::get('/specs/:format')
'description' => 'Your project ID',
'in' => 'header',
],
'JWT' => [
'type' => 'apiKey',
'name' => 'X-Appwrite-JWT',
'description' => 'Your secret JSON Web Token',
'in' => 'header',
],
'Locale' => [
'type' => 'apiKey',
'name' => 'X-Appwrite-Locale',
@ -246,6 +252,12 @@ App::get('/specs/:format')
'description' => 'Your secret API key',
'in' => 'header',
],
'JWT' => [
'type' => 'apiKey',
'name' => 'X-Appwrite-JWT',
'description' => 'Your secret JSON Web Token',
'in' => 'header',
],
'Locale' => [
'type' => 'apiKey',
'name' => 'X-Appwrite-Locale',
@ -266,6 +278,12 @@ App::get('/specs/:format')
'description' => 'Your secret API key',
'in' => 'header',
],
'JWT' => [
'type' => 'apiKey',
'name' => 'X-Appwrite-JWT',
'description' => 'Your secret JSON Web Token',
'in' => 'header',
],
'Locale' => [
'type' => 'apiKey',
'name' => 'X-Appwrite-Locale',
@ -281,14 +299,32 @@ App::get('/specs/:format')
],
];
$security = [
APP_PLATFORM_CLIENT => ['Project' => []],
APP_PLATFORM_SERVER => ['Project' => [], 'Key' => []],
APP_PLATFORM_CONSOLE => ['Project' => [], 'Key' => []],
];
foreach ($utopia->getRoutes() as $key => $method) {
foreach ($method as $route) { /** @var \Utopia\Route $route */
$routeSecurity = $route->getLabel('sdk.auth', []);
$sdkPlatofrms = [];
foreach ($routeSecurity as $value) {
switch ($value) {
case APP_AUTH_TYPE_SESSION:
$sdkPlatofrms[] = APP_PLATFORM_CLIENT;
break;
case APP_AUTH_TYPE_KEY:
$sdkPlatofrms[] = APP_PLATFORM_SERVER;
break;
case APP_AUTH_TYPE_JWT:
$sdkPlatofrms[] = APP_PLATFORM_SERVER;
break;
case APP_AUTH_TYPE_ADMIN:
$sdkPlatofrms[] = APP_PLATFORM_CONSOLE;
break;
}
}
if(empty($routeSecurity)) {
$sdkPlatofrms[] = APP_PLATFORM_CLIENT;
}
if (!$route->getLabel('docs', true)) {
continue;
}
@ -305,7 +341,7 @@ App::get('/specs/:format')
continue;
}
if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $route->getLabel('sdk.platform', []))) {
if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $sdkPlatofrms)) {
continue;
}
@ -342,11 +378,11 @@ App::get('/specs/:format')
switch ($format) {
case 'swagger2':
$format = new Swagger2($utopia, $services, $routes, $models, $keys[$platform], $security[$platform]);
$format = new Swagger2($utopia, $services, $routes, $models, $keys[$platform]);
break;
case 'open-api3':
$format = new OpenAPI3($utopia, $services, $routes, $models, $keys[$platform], $security[$platform]);
$format = new OpenAPI3($utopia, $services, $routes, $models, $keys[$platform]);
break;
default:

View file

@ -68,6 +68,11 @@ const DELETE_TYPE_EXECUTIONS = 'executions';
const DELETE_TYPE_AUDIT = 'audit';
const DELETE_TYPE_ABUSE = 'abuse';
const DELETE_TYPE_CERTIFICATES = 'certificates';
// Auth Types
const APP_AUTH_TYPE_SESSION = 'Session';
const APP_AUTH_TYPE_JWT = 'JWT';
const APP_AUTH_TYPE_KEY = 'Key';
const APP_AUTH_TYPE_ADMIN = 'Admin';
$register = new Registry();
@ -77,10 +82,11 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION));
* ENV vars
*/
Config::load('events', __DIR__.'/config/events.php');
Config::load('auth', __DIR__.'/config/auth.php');
Config::load('providers', __DIR__.'/config/providers.php');
Config::load('platforms', __DIR__.'/config/platforms.php');
Config::load('collections', __DIR__.'/config/collections.php');
Config::load('environments', __DIR__.'/config/environments.php');
Config::load('runtimes', __DIR__.'/config/runtimes.php');
Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes
Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes
Config::load('services', __DIR__.'/config/services.php'); // List of services
@ -177,8 +183,9 @@ $register->set('influxdb', function () { // Register DB connection
if (empty($host) || empty($port)) {
return;
}
$client = new InfluxDB\Client($host, $port, '', '', false, false, 5);
$driver = new InfluxDB\Driver\Curl(dsn: "http://{$host}:{$port}");
$client = new InfluxDB\Client(host: $host, port: $port, timeout: 5);
$client->setDriver($driver);
return $client;
});

View file

@ -36,7 +36,7 @@ $cli
$projects = [$console];
$count = 0;
$migration = new Version\V06($register->get('db')); //TODO: remove hardcoded version and move to dynamic migration
$migration = new Version\V07($register->get('db')); //TODO: remove hardcoded version and move to dynamic migration
while ($sum > 0) {
foreach ($projects as $project) {

View file

@ -42,7 +42,7 @@ $cli
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
if(!in_array($version, ['0.6.x', '0.7.x'])) {
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x'])) {
throw new Exception('Unknown version given');
}

View file

@ -521,7 +521,7 @@ $maxCells = 10;
<div data-ls-loop="project-collections.collections" data-ls-as="project" data-ls-key="$index2" class="tiles cell-3 margin-bottom-negative">
<div class="margin-bottom" data-ls-if="{{project.$id}} != {{router.params.id}}">
<input type="radio" name="list" data-ls-attrs="value={{project.$id}},id={{project.$id}}" data-ls-bind="{{rule.list|firstElement}}" data-cast-to="array" required />
<input type="radio" data-ls-attrs="value={{project.$id}},id=[{{rule.$id}}].{{project.$id}},name=[{{rule.$id}}].list" data-ls-bind="{{rule.list|firstElement}}" data-cast-to="array" required />
<label data-ls-attrs="for={{project.$id}}"data-ls-bind="{{project.name}}"></label>
</div>
</div>

View file

@ -46,7 +46,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
<div class="box margin-bottom-large">
<div class="text-align-center">
<img src="" data-ls-attrs="src=/images/environments/{{project-function.env|envLogo}}" alt="Function Env." class="avatar huge margin-top-negative-xxl" />
<img src="" data-ls-attrs="src=/images/runtimes/{{project-function.env|envLogo}}" alt="Function Env." class="avatar huge margin-top-negative-xxl" />
<p class="text-fade margin-bottom-small" data-ls-bind="{{project-function.env|envName}} {{project-function.env|envVersion}}">
</p>

View file

@ -1,5 +1,5 @@
<?php
$environments = $this->getParam('environments', []);
$runtimes = $this->getParam('runtimes', []);
?>
<div class="cover">
<h1 class="zone xl margin-bottom-large">
@ -40,7 +40,7 @@ $environments = $this->getParam('environments', []);
<ul data-ls-loop="project-functions.functions" data-ls-as="function" class="list">
<li class="clear">
<div class="pull-start margin-end avatar-container">
<img src="" data-ls-attrs="src=/images/environments/{{function.env|envLogo}}?v=<?php echo APP_CACHE_BUSTER; ?>" alt="Function Env." class="avatar" loading="lazy" width="60" height="60" />
<img src="" data-ls-attrs="src=/images/runtimes/{{function.env|envLogo}}?v=<?php echo APP_CACHE_BUSTER; ?>" alt="Function Env." class="avatar" loading="lazy" width="60" height="60" />
</div>
<a data-ls-attrs="href=/console/functions/function?id={{function.$id}}&project={{router.params.project}}" class="button pull-end">Settings</a>
@ -109,10 +109,10 @@ $environments = $this->getParam('environments', []);
<label for="name">Name</label>
<input type="text" id="name" name="name" required autocomplete="off" class="margin-bottom" maxlength="128" />
<label for="env">Environment</label>
<label for="env">Runtimes</label>
<select name="env" id="env" required class="margin-bottom-xl">
<?php foreach($environments as $key => $environment): ?>
<option value="<?php echo $this->escape($key); ?>"><?php echo $this->escape($environment['name']); ?> <?php echo $this->escape($environment['version']); ?></option>
<?php foreach($runtimes as $key => $runtime): ?>
<option value="<?php echo $this->escape($key); ?>"><?php echo $this->escape($runtime['name']); ?> <?php echo $this->escape($runtime['version']); ?></option>
<?php endforeach; ?>
</select>

View file

@ -1,5 +1,6 @@
<?php
$providers = $this->getParam('providers', []);
$auth = $this->getParam('auth', []);
?>
<div class="cover">
@ -300,9 +301,98 @@ $providers = $this->getParam('providers', []);
</li>
<li data-state="/console/users/providers?project={{router.params.project}}">
<h2>OAuth2 Providers</h2>
<p data-ls-if="{{console-project.usersAuthLimit}} == 0" class="text-fade text-size-small margin-bottom pull-end">Unlimited Users <span class="link" data-ls-ui-trigger="project-update-auth-users-limit">Set Limit</a></p>
<p data-ls-if="{{console-project.usersAuthLimit}} != 0" class="text-fade text-size-small margin-bottom pull-end"><span data-ls-bind="{{console-project.usersAuthLimit|statsTotal}}"></span> Users allowed <span class="link" data-ls-ui-trigger="project-update-auth-users-limit">Change Limit</a></p>
<h2>Settings</h2>
<div class="margin-bottom margin-top-large"
<div data-ui-modal class="modal close" data-button-alias="none" data-open-event="project-update-auth-users-limit">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h1>Max Allowed Users</h1>
<form data-debug="1"
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Update Project Users Limit"
data-service="projects.updateAuthLimit"
data-scope="console"
data-event="submit"
data-param-project-id="{{router.params.project}}"
data-success="alert,trigger"
data-success-param-alert-text="Updated project users limit successfully"
data-success-param-trigger-events="projects.update"
data-failure="alert"
data-failure-param-alert-text="Failed to update project users limit"
data-failure-param-alert-classname="error">
<input name="limit" id="users-limit" type="number" data-ls-bind="{{console-project.usersAuthLimit}}" data-cast-to="numeric" min="0" />
<div class="info row thin margin-bottom margin-top">
<div class="col span-1">
<i class="icon-info-circled text-sign"></i>
</div>
<div class="col span-11">This limit will prevent new users from signing up for your project, no matter what auth method has been used. You will still be able to create users and team memberships from your Appwrite console. For an unlimited amount of users, set the limit to 0.</div>
</div>
<button>Update</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</form>
</div>
<p class="text-fade margin-bottom">Choose auth methods you wish to use.</p>
<ul class="tiles cell-3 margin-bottom-small">
<?php foreach($auth as $index => $method):
$key = $method['key'] ?? '';
$name = $method['name'] ?? '';
$icon = $method['icon'] ?? '';
$docs = $method['docs'] ?? '';
$enabled = $method['enabled'] ?? false;
?>
<li class="">
<div class="box padding-small margin-bottom clear">
<?php if($enabled): ?>
<form
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Update Project Auth Status (<?php echo $this->escape($name); ?>)"
data-service="projects.updateAuthStatus"
data-scope="console"
data-event="change"
data-param-project-id="{{router.params.project}}"
data-success="alert,trigger"
data-success-param-alert-text="Updated project auth status successfully"
data-success-param-trigger-events="projects.update"
data-failure="alert"
data-failure-param-alert-text="Failed to update project auth status settings"
data-failure-param-alert-classname="error">
<input name="method" id="<?php echo $this->escape($key); ?>" type="hidden" autocomplete="off" value="<?php echo $this->escape($index); ?>">
<input name="status" type="hidden" data-forms-switch data-ls-bind="{{console-project.<?php echo $this->escape($key); ?>}}" data-cast-to="boolean" class="pull-end" />
</form>
<?php endif; ?>
<img src="<?php echo $this->escape($icon); ?>?buster=<?php echo APP_CACHE_BUSTER; ?>" alt="Email/Password Logo" class="pull-start provider margin-end" />
<span class="text-size-small"><?php echo $this->escape($name); ?><?php if(!$enabled): ?> <spann class="text-fade text-size-xs">soon</span><?php endif; ?></span>
<?php if($docs): ?>
<p class="margin-bottom-no text-one-liner text-size-small">
<a href="<?php echo $this->escape($docs); ?>" target="_blank" rel="noopener">Docs<i class="icon-link-ext"></i></a>
</p>
<?php endif; ?>
</div>
</li>
<?php endforeach; ?>
</ul>
<h3>OAuth2 Providers</h3>
<div class="margin-bottom margin-top"
data-service="projects.get"
data-event="load,projects.create,projects.update,projects.deleteProject"
data-name="console-project"
@ -312,6 +402,7 @@ $providers = $this->getParam('providers', []);
<?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;
@ -320,7 +411,7 @@ $providers = $this->getParam('providers', []);
<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>
<h1><?php echo $this->escape($name); ?> OAuth2 Settings</h1>
<h1><?php echo $this->escape($name); ?> <?php if($sandbox): ?>Sandbox<?php endif; ?> OAuth2 Settings</h1>
<form
data-analytics
@ -383,10 +474,10 @@ $providers = $this->getParam('providers', []);
<button class="switch pull-end" data-ls-ui-trigger="provider-update-<?php echo $this->escape($provider); ?>"></button>
</span>
<img src="/images/oauth2/<?php echo $this->escape(strtolower($provider)); ?>.png?buster=<?php echo APP_CACHE_BUSTER; ?>" alt="<?php echo $this->escape(ucfirst($provider)); ?> Logo" class="pull-start provider margin-end" />
<img src="/images/users/oauth2/<?php echo $this->escape(strtolower($provider)); ?>.png?buster=<?php echo APP_CACHE_BUSTER; ?>" alt="<?php echo $this->escape(ucfirst($provider)); ?> Logo" class="pull-start provider margin-end" />
<span class="text-size-small">
<?php echo $this->escape($name); ?> <?php if($beta): ?>(beta)<?php endif; ?>
<?php echo $this->escape($name); ?> <?php if($sandbox): ?><span class="text-size-xs text-fade">sandbox</span><?php endif; ?> <?php if($beta): ?><span class="text-size-xs text-fade">beta</span><?php endif; ?>
</span>
<p class="margin-bottom-no text-one-liner text-size-small">

View file

@ -102,7 +102,7 @@ services:
- _APP_FUNCTIONS_CPUS
- _APP_FUNCTIONS_MEMORY
- _APP_FUNCTIONS_MEMORY_SWAP
- _APP_FUNCTIONS_ENVS
- _APP_FUNCTIONS_RUNTIMES
appwrite-realtime:
entrypoint: realtime
@ -314,6 +314,7 @@ services:
- _APP_FUNCTIONS_CPUS
- _APP_FUNCTIONS_MEMORY
- _APP_FUNCTIONS_MEMORY_SWAP
- _APP_FUNCTIONS_RUNTIMES
- _APP_USAGE_STATS
appwrite-worker-mails:

View file

@ -11,7 +11,7 @@ $analytics = $this->getParam('analytics', 'UA-26264668-9');
$mode = $this->getParam('mode', '');
$canonical = $this->getParam('canonical', '');
$locale = $this->getParam('locale', null);
$environments = $this->getParam('environments', null);
$runtimes = $this->getParam('runtimes', null);
if(!empty($platforms)) {
$platforms = array_map(function($platform) {
@ -78,7 +78,7 @@ if(!empty($platforms)) {
SETUP: '<?php echo $this->escape($this->getParam('setup')); ?>',
API: '/v1',
PROJECT: 'console',
ENVIRONMENTS: <?php echo json_encode($environments); ?>,
RUNTIMES: <?php echo json_encode($runtimes); ?>,
PLATFORMS: <?php echo json_encode($platforms); ?>,
LOCALE: '<?php echo $this->escape($locale->getText('settings.locale')); ?>',
PREFIX: '<?php echo $this->escape($this->getParam('prefix')); ?>',

View file

@ -16,21 +16,19 @@ use Utopia\Config\Config;
require_once __DIR__.'/../workers.php';
Runtime::enableCoroutine(0);
Console::title('Functions V1 Worker');
Runtime::setHookFlags(SWOOLE_HOOK_ALL);
Console::success(APP_NAME.' functions worker v1 has started');
$environments = Config::getParam('environments');
$runtimes = Config::getParam('runtimes');
/**
* Warmup Docker Images
*/
$warmupStart = \microtime(true);
Co\run(function() use ($environments) { // Warmup: make sure images are ready to run fast 🚀
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
Co\run(function() use ($runtimes) { // Warmup: make sure images are ready to run fast 🚀
$dockerUser = App::getEnv('DOCKERHUB_PULL_USERNAME', null);
$dockerPass = App::getEnv('DOCKERHUB_PULL_PASSWORD', null);
@ -43,14 +41,14 @@ Co\run(function() use ($environments) { // Warmup: make sure images are ready t
Console::log('Docker Login'. $stdout.$stderr);
}
foreach($environments as $environment) {
go(function() use ($environment) {
foreach($runtimes as $runtime) {
go(function() use ($runtime) {
$stdout = '';
$stderr = '';
Console::info('Warming up '.$environment['name'].' '.$environment['version'].' environment...');
Console::info('Warming up '.$runtime['name'].' '.$runtime['version'].' environment...');
Console::execute('docker pull '.$environment['image'], '', $stdout, $stderr);
Console::execute('docker pull '.$runtime['image'], '', $stdout, $stderr);
if(!empty($stdout)) {
Console::log($stdout);
@ -295,7 +293,7 @@ class FunctionsV1 extends Worker
{
global $list;
$environments = Config::getParam('environments');
$runtimes = Config::getParam('runtimes');
Authorization::disable();
$tag = $database->getDocument($function->getAttribute('tag', ''));
@ -329,11 +327,11 @@ class FunctionsV1 extends Worker
Authorization::reset();
$environment = (isset($environments[$function->getAttribute('env', '')]))
? $environments[$function->getAttribute('env', '')]
$runtime = (isset($runtimes[$function->getAttribute('env', '')]))
? $runtimes[$function->getAttribute('env', '')]
: null;
if(\is_null($environment)) {
if(\is_null($runtime)) {
throw new Exception('Environment "'.$function->getAttribute('env', '').' is not supported');
}
@ -342,8 +340,8 @@ class FunctionsV1 extends Worker
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
'APPWRITE_FUNCTION_ENV_NAME' => $environment['name'],
'APPWRITE_FUNCTION_ENV_VERSION' => $environment['version'],
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
'APPWRITE_FUNCTION_EVENT' => $event,
'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
'APPWRITE_FUNCTION_DATA' => $data,
@ -421,7 +419,7 @@ class FunctionsV1 extends Worker
" --volume {$tagPathTargetDir}:/tmp:rw".
" --workdir /usr/local/src".
" ".\implode(" ", $vars).
" {$environment['image']}".
" {$runtime['image']}".
" sh -c 'mv /tmp/code.tar.gz /usr/local/src/code.tar.gz && tar -zxf /usr/local/src/code.tar.gz --strip 1 && rm /usr/local/src/code.tar.gz && tail -f /dev/null'"
, '', $stdout, $stderr, 30);

View file

@ -28,23 +28,23 @@ class UsageV1 extends Worker
/** @var \Domnikl\Statsd\Client $statsd */
$statsd = $register->get('statsd', true);
$projectId = $this->args['projectId'];
$projectId = $this->args['projectId'] ?? '';
$storage = $this->args['storage'] ?? 0;
$networkRequestSize = $this->args['networkRequestSize'] ?? 0;
$networkResponseSize = $this->args['networkResponseSize'] ?? 0;
$storage = $this->args['storage'] ?? null;
$httpMethod = $this->args['httpMethod'] ?? null;
$httpRequest = $this->args['httpRequest'] ?? null;
$httpMethod = $this->args['httpMethod'] ?? '';
$httpRequest = $this->args['httpRequest'] ?? 0;
$functionId = $this->args['functionId'] ?? null;
$functionExecution = $this->args['functionExecution'] ?? null;
$functionExecutionTime = $this->args['functionExecutionTime'] ?? null;
$functionStatus = $this->args['functionStatus'] ?? null;
$functionId = $this->args['functionId'];
$functionExecution = $this->args['functionExecution'] ?? 0;
$functionExecutionTime = $this->args['functionExecutionTime'] ?? 0;
$functionStatus = $this->args['functionStatus'] ?? '';
$realtimeConnections = $this->args['realtimeConnections'] ?? null;
$realtimeMessages = $this->args['realtimeMessages'] ?? null;
$realtimeConnections = $this->args['realtimeConnections'] ?? 0;
$realtimeMessages = $this->args['realtimeMessages'] ?? 0;
$tags = ",project={$projectId},version=".App::getEnv('_APP_VERSION', 'UNKNOWN');

View file

@ -21,7 +21,7 @@
}
},
"require": {
"php": ">=7.4.0",
"php": ">=8.0.0",
"ext-curl": "*",
"ext-imagick": "*",
"ext-mbstring": "*",
@ -35,39 +35,38 @@
"ext-zlib": "*",
"ext-sockets": "*",
"appwrite/php-clamav": "1.0.*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.2.*",
"utopia-php/framework": "0.12.*",
"utopia-php/abuse": "0.4.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.5.*",
"utopia-php/cache": "0.2.*",
"utopia-php/cli": "0.10.0",
"utopia-php/cli": "0.10.*",
"utopia-php/config": "0.2.*",
"utopia-php/locale": "0.3.*",
"utopia-php/registry": "master",
"utopia-php/registry": "0.4.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/domains": "0.2.*",
"utopia-php/domains": "1.1.*",
"utopia-php/swoole": "0.2.*",
"utopia-php/system": "0.4.*",
"utopia-php/storage": "0.4.*",
"utopia-php/image": "0.1.*",
"utopia-php/image": "0.2.*",
"resque/php-resque": "1.3.6",
"matomo/device-detector": "4.1.0",
"matomo/device-detector": "4.2.2",
"dragonmantank/cron-expression": "3.1.0",
"influxdb/influxdb-php": "1.15.2",
"phpmailer/phpmailer": "6.3.0",
"phpmailer/phpmailer": "6.4.0",
"chillerlan/php-qrcode": "4.3.0",
"adhocore/jwt": "1.1.2",
"slickdeals/statsd": "~3.0"
"slickdeals/statsd": "3.0.2"
},
"require-dev": {
"appwrite/sdk-generator": "0.7.0",
"phpunit/phpunit": "9.4.2",
"swoole/ide-helper": "4.5.5",
"appwrite/sdk-generator": "dev-feat-preps-for-0.8",
"swoole/ide-helper": "4.6.6",
"textalk/websocket": "1.5.2",
"vimeo/psalm": "4.1.1"
"phpunit/phpunit": "9.5.4",
"vimeo/psalm": "4.7.1"
},
"repositories": [
{
@ -78,10 +77,9 @@
"provide": {
"ext-phpiredis": "*"
},
"minimum-stability": "dev",
"config": {
"platform": {
"php": "7.4"
"php": "8.0"
}
}
}

901
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -119,7 +119,7 @@ services:
- _APP_FUNCTIONS_CPUS
- _APP_FUNCTIONS_MEMORY
- _APP_FUNCTIONS_MEMORY_SWAP
- _APP_FUNCTIONS_ENVS
- _APP_FUNCTIONS_RUNTIMES
appwrite-realtime:
entrypoint: realtime
@ -334,7 +334,6 @@ services:
- /tmp:/tmp:rw
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
- ./docker:/usr/src/code/docker
depends_on:
- redis
- mariadb
@ -351,6 +350,7 @@ services:
- _APP_DB_PASS
- _APP_FUNCTIONS_TIMEOUT
- _APP_FUNCTIONS_CONTAINERS
- _APP_FUNCTIONS_RUNTIMES
- _APP_FUNCTIONS_CPUS
- _APP_FUNCTIONS_MEMORY
- _APP_FUNCTIONS_MEMORY_SWAP
@ -474,7 +474,7 @@ services:
# - appwrite-uploads:/storage/uploads
influxdb:
image: influxdb:1.8-alpine
image: appwrite/influxdb:1.0.0
container_name: appwrite-influxdb
networks:
- appwrite
@ -482,7 +482,7 @@ services:
- appwrite-influxdb:/var/lib/influxdb:rw
telegraf:
image: appwrite/telegraf:1.0.0
image: appwrite/telegraf:1.1.0
container_name: appwrite-telegraf
networks:
- appwrite
@ -501,16 +501,16 @@ services:
# Webgrind - A nice UI for exploring and debugging code-level stuff
maildev: # used mainly for dev tests
image: djfarrelly/maildev
container_name: appwrite-maildev
image: appwrite/mailcatcher:1.0.0
container_name: appwrite-mailcatcher
ports:
- '9503:80'
- '9503:1080'
networks:
- appwrite
request-catcher: # used mainly for dev tests
image: smarterdm/http-request-catcher
container_name: appwrite-request-catcher
image: appwrite/requestcatcher:1.0.0
container_name: appwrite-requestcatcher
ports:
- '9504:5000'
networks:
@ -518,6 +518,7 @@ services:
adminer:
image: adminer
container_name: appwrite-adminer
restart: always
ports:
- 9506:8080

View file

@ -1,13 +0,0 @@
# Appwrite Functions Environments
Docker based enviornments for Appwrite Functions. You can use this Docker images to locally tests your functions by executing them on your local desktop or server.
All the supported enviornments are based on Docker Alpine images.
## Build
Build envs for all supported cloud functions (multicore builds)
```bash
bash ./docker/environments/build.sh
```

View file

@ -1,46 +0,0 @@
echo 'Starting build...'
echo 'Deno 1.2...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.2:1.0.0 ./docker/environments/deno-1.2/ --push
echo 'Deno 1.5...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.5:1.0.0 ./docker/environments/deno-1.5/ --push
echo 'Deno 1.6...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.6:1.0.0 ./docker/environments/deno-1.6/ --push
echo 'Node 14.5...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le -t appwrite/env-node-14.5:1.0.0 ./docker/environments/node-14.5/ --push
echo 'Node 15.5...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le -t appwrite/env-node-15.5:1.0.0 ./docker/environments/node-15.5/ --push
echo 'PHP 7.4...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-php-7.4:1.0.0 ./docker/environments/php-7.4/ --push
echo 'PHP 8.0...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-php-8.0:1.0.0 ./docker/environments/php-8.0/ --push
echo 'Python 3.8...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-python-3.8:1.0.0 ./docker/environments/python-3.8/ --push
echo 'Python 3.9...'
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-python-3.9:1.0.0 ./docker/environments/python-3.9/ --push
echo 'Ruby 2.7...'
docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-ruby-2.7:1.0.2 ./docker/environments/ruby-2.7/ --push
echo 'Ruby 3.0...'
docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-ruby-3.0:1.0.0 ./docker/environments/ruby-3.0/ --push
echo 'Dart 2.10...'
docker buildx build --platform linux/amd64 -t appwrite/env-dart-2.10:1.0.0 ./docker/environments/dart-2.10/ --push
echo 'Dart 2.12...'
docker buildx build --platform linux/amd64 -t appwrite/env-dart-2.12:1.0.0 ./docker/environments/dart-2.12/ --push
echo '.NET 3.1...'
docker buildx build --platform linux/amd64,linux/arm64 -t appwrite/env-dotnet-3.1:1.0.0 ./docker/environments/dotnet-3.1/ --push
echo '.NET 5.0...'
docker buildx build --platform linux/amd64,linux/arm64 -t appwrite/env-dotnet-5.0:1.0.0 ./docker/environments/dotnet-5.0/ --push

View file

@ -1,9 +0,0 @@
FROM google/dart:2.10
LABEL maintainer="team@appwrite.io"
RUN apt-get update -y && apt-get install -y tar
WORKDIR /usr/local/src/
ENV PUB_CACHE=/usr/local/src/.appwrite

View file

@ -1,9 +0,0 @@
FROM google/dart:2.12
LABEL maintainer="team@appwrite.io"
RUN apt-get update -y && apt-get install -y tar
WORKDIR /usr/local/src/
ENV PUB_CACHE=/usr/local/src/.appwrite

View file

@ -1,11 +0,0 @@
FROM hayd/deno:alpine-1.2.0
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV DENO_DIR=/usr/local/src/.appwrite

View file

@ -1,11 +0,0 @@
FROM hayd/deno:alpine-1.5.0
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV DENO_DIR=/usr/local/src/.appwrite

View file

@ -1,11 +0,0 @@
FROM hayd/deno:alpine-1.6.2
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV DENO_DIR=/usr/local/src/.appwrite

View file

@ -1,7 +0,0 @@
FROM mcr.microsoft.com/dotnet/runtime:3.1-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
WORKDIR /usr/local/src/

View file

@ -1,7 +0,0 @@
FROM mcr.microsoft.com/dotnet/runtime:5.0-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
WORKDIR /usr/local/src/

View file

@ -1,9 +0,0 @@
FROM node:14.5-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/

View file

@ -1,9 +0,0 @@
FROM node:15.5-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/

View file

@ -1,9 +0,0 @@
FROM php:7.4-cli-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/

View file

@ -1,9 +0,0 @@
FROM php:8.0-cli-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/

View file

@ -1,11 +0,0 @@
FROM python:3.8-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV PYTHONPATH "${PYTHONPATH}:/usr/local/src/.appwrite"

View file

@ -1,11 +0,0 @@
FROM python:3.9-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV PYTHONPATH "${PYTHONPATH}:/usr/local/src/.appwrite"

View file

@ -1,12 +0,0 @@
FROM ruby:2.7-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV GEM_PATH=/usr/local/src/.appwrite
ENV GEM_SPEC_CACHE=/usr/local/src/.appwrite/specs

View file

@ -1,12 +0,0 @@
FROM ruby:3.0-alpine
LABEL maintainer="team@appwrite.io"
RUN apk add tar
RUN mkdir /usr/local/src
WORKDIR /usr/local/src/
ENV GEM_PATH=/usr/local/src/.appwrite
ENV GEM_SPEC_CACHE=/usr/local/src/.appwrite/specs

View file

@ -0,0 +1,15 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = sdk.projects.updateAuthLimit('[PROJECT_ID]', '');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,15 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = sdk.projects.updateAuthStatus('[PROJECT_ID]', 'email-password', false);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,13 @@
# Multi Architecture Support
A list of Appwrite CPU architecture support status. We use this list to track the status of all Appwrite related Docker images and which architecture is supported by each image.
| | linux/amd64 | linux/arm64 | linux/arm/v6 | linux/arm/v7 | linux/arm64/v8 | linux/ppc64le | linux/s390x |
|---|---|---|---|---|---|---|---|
| appwrite/appwrite | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 |
| appwrite/mariadb | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 |
| appwrite/influxdb | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 |
| appwrite/telegraf | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 |
| appwrite/clamav | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🟢 | 🟢 |
| traefik | 🟢 | 🔴 | 🟢 | 🔴 | 🟢 | 🔴 | 🔴 |
| redis | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 |

View file

@ -12,25 +12,27 @@
<extension class="Appwrite\Tests\TestHook" />
</extensions>
<testsuites>
<testsuite name="Application Test Suite">
<testsuite name="unit">
<directory>./tests/unit/</directory>
</testsuite>
<testsuite name="e2e">
<file>./tests/e2e/Client.php</file>
<directory>./tests/e2e/General</directory>
<directory>./tests/e2e/Scopes</directory>
<directory>./tests/e2e/Services/Projects</directory>
<directory>./tests/e2e/Services/Account</directory>
<directory>./tests/e2e/Services/Avatars</directory>
<directory>./tests/e2e/Services/Database</directory>
<file>./tests/e2e/Services/Functions/FunctionsBase.php</file>
<file>./tests/e2e/Services/Functions/FunctionsCustomServerTest.php</file>
<file>./tests/e2e/Services/Functions/FunctionsCustomClientTest.php</file>
<directory>./tests/e2e/Services/Health</directory>
<directory>./tests/e2e/Services/Locale</directory>
<directory>./tests/e2e/Services/Projects</directory>
<directory>./tests/e2e/Services/Storage</directory>
<directory>./tests/e2e/Services/Teams</directory>
<directory>./tests/e2e/Services/Users</directory>
<directory>./tests/e2e/Services/Webhooks</directory>
<directory>./tests/e2e/Services/Workers</directory>
<directory>./tests/unit/</directory>
<directory>./tests/e2e/Services/Webhooks</directory>
<file>./tests/e2e/Services/Functions/FunctionsBase.php</file>
<file>./tests/e2e/Services/Functions/FunctionsCustomServerTest.php</file>
<file>./tests/e2e/Services/Functions/FunctionsCustomClientTest.php</file>
</testsuite>
</testsuites>
</phpunit>

View file

@ -27,7 +27,7 @@ return http.post(path,{'content-type':'application/json',},payload);},delete:fun
if(password===undefined){throw new Error('Missing required parameter: "password"');}
let path='/account/email';let payload={};if(email){payload['email']=email;}
if(password){payload['password']=password;}
return http.patch(path,{'content-type':'application/json',},payload);},createJWT:function(){let path='/account/jwt';let payload={};return http.post(path,{'content-type':'application/json',},payload);},getLogs:function(){let path='/account/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},updateName:function(name){if(name===undefined){throw new Error('Missing required parameter: "name"');}
return http.patch(path,{'content-type':'application/json',},payload);},getLogs:function(){let path='/account/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},updateName:function(name){if(name===undefined){throw new Error('Missing required parameter: "name"');}
let path='/account/name';let payload={};if(name){payload['name']=name;}
return http.patch(path,{'content-type':'application/json',},payload);},updatePassword:function(password,oldPassword){if(password===undefined){throw new Error('Missing required parameter: "password"');}
if(oldPassword===undefined){throw new Error('Missing required parameter: "oldPassword"');}
@ -244,7 +244,14 @@ if(legalTaxId){payload['legalTaxId']=legalTaxId;}
return http.patch(path,{'content-type':'application/json',},payload);},delete:function(projectId,password){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(password===undefined){throw new Error('Missing required parameter: "password"');}
let path='/projects/{projectId}'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(password){payload['password']=password;}
return http.delete(path,{'content-type':'application/json',},payload);},listDomains:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
return http.delete(path,{'content-type':'application/json',},payload);},updateAuthLimit:function(projectId,limit){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(limit===undefined){throw new Error('Missing required parameter: "limit"');}
let path='/projects/{projectId}/auth/limit'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(typeof limit!=='undefined'){payload['limit']=limit;}
return http.patch(path,{'content-type':'application/json',},payload);},updateAuthStatus:function(projectId,method,status){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(method===undefined){throw new Error('Missing required parameter: "method"');}
if(status===undefined){throw new Error('Missing required parameter: "status"');}
let path='/projects/{projectId}/auth/{method}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{method}','g'),method);let payload={};if(status){payload['status']=status;}
return http.patch(path,{'content-type':'application/json',},payload);},listDomains:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/domains'.replace(new RegExp('{projectId}','g'),projectId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createDomain:function(projectId,domain){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(domain===undefined){throw new Error('Missing required parameter: "domain"');}
let path='/projects/{projectId}/domains'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(domain){payload['domain']=domain;}
@ -2212,9 +2219,11 @@ match=text.match(new RegExp(regex,'gi'))
if(!match){return fail}
for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}}
return(date.getTime()/1000)}
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){if(value&&Array.isArray(value)&&to!=='array'){value=value.map(element=>cast(element,to));return value;}
switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return value;}
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if(name.startsWith('[')){let splitName=name.split('.');if(splitName.length>1&&splitName[0].endsWith(']')){name=splitName[splitName.length-1];}}
if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}
ref=json[name];}
else{if(!Array.isArray(json[name])){json[name]=[];}
json[name].push({});ref=json[name][json[name].length-1];}}
@ -2260,9 +2269,9 @@ return result.length;}).add("documentAction",function(container){let collection=
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
return'';}).add("firstElement",function($value){if($value&&$value[0]){return $value[0];}
return $value;}).add("platformsLimit",function($value){return $value;}).add("limit",function($value){let postfix=($value.length>=50)?'...':'';return $value.substring(0,50)+postfix;;}).add("arraySentence",function($value){if(!Array.isArray($value)){return'';}
return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("envName",function($value,env){if(env&&env.ENVIRONMENTS&&env.ENVIRONMENTS[$value]){return env.ENVIRONMENTS[$value].name;}
return'';}).add("envLogo",function($value,env){if(env&&env.ENVIRONMENTS&&env.ENVIRONMENTS[$value]){return env.ENVIRONMENTS[$value].logo;}
return'';}).add("envVersion",function($value,env){if(env&&env.ENVIRONMENTS&&env.ENVIRONMENTS[$value]){return env.ENVIRONMENTS[$value].version;}
return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("envName",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].name;}
return'';}).add("envLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].logo;}
return'';}).add("envVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;}
return'';});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);}
@ -2282,8 +2291,8 @@ if(element.array){document[element.key]=[];}}}}}};let getParams=function getPara
while((match=REGEX_PARAMETERS_VALUES.exec(functionAsString))){params.push(match[1]);}
return params;};let getValue=function(key,prefix,data){let result=null;if(!key){return null;}
let attrKey=prefix+key.charAt(0).toUpperCase()+key.slice(1);if(element.dataset[attrKey]){result=expression.parse(element.dataset[attrKey]);if(element.dataset[attrKey+"CastTo"]==="array"){result=result.split(",");}}
if(data[key]){result=data[key];}
if(!result){result="";}
if(typeof data[key]!=='undefined'){result=data[key];}
if(typeof result==='undefined'){result="";}
return result;};let resolve=function(target,prefix="param",data={}){if(!target){return function(){};}
let args=getParams(target);return target.apply(target,args.map(function(value){let result=getValue(value,prefix,data);return result;}));};let exec=function(event){let parsedSuccess=expression.parse(success);let parsedFailure=expression.parse(failure);let parsedAction=expression.parse(action);parsedSuccess=parsedSuccess&&parsedSuccess!=""?parsedSuccess.split(",").map(element=>element.trim()):[];parsedFailure=parsedFailure&&parsedFailure!=""?parsedFailure.split(",").map(element=>element.trim()):[];element.$lsSkip=true;element.classList.add("load-service-start");if(!document.body.contains(element)){element=undefined;return false;}
if(event){event.preventDefault();}
@ -2348,7 +2357,7 @@ score+=(variationCount-1)*10;return parseInt(score);};var callback=function(){va
if(rtl.isRTL(content)){paragraph.style.direction='rtl';paragraph.style.textAlign='right';}
else{paragraph.style.direction='ltr';paragraph.style.textAlign='left';}
last=paragraph;}};var santize=function(e){clean(e);alignText(e);};element.addEventListener("change",function(){editor.content.innerHTML=markdown.render(element.value);alignText();});editor.content.setAttribute("placeholder",element.placeholder);editor.content.innerHTML=markdown.render(element.value);editor.content.tabIndex=0;alignText();editor.content.onkeydown=function preventTab(event){if(event.which===9){event.preventDefault();if(document.activeElement){var focussable=Array.prototype.filter.call(document.querySelectorAll('a:not([disabled]), button:not([disabled]), select:not([disabled]), input[type=text]:not([disabled]), input[type=checkbox]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])'),function(element){return(element.offsetWidth>0||element.offsetHeight>0||element===document.activeElement);});var index=focussable.indexOf(document.activeElement);if(index>-1){if(event.shiftKey){var prevElement=focussable[index-1]||focussable[focussable.length-1];prevElement.focus();}else{var nextElement=focussable[index+1]||focussable[0];nextElement.focus();}}}}};div.addEventListener("paste",santize);div.addEventListener("drop",santize);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-remove",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-remove]")).map(function(obj){obj.addEventListener("click",function(){element.parentNode.removeChild(element);});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-run",repeat:false,controller:function(element,expression,container){let action=expression.parse(element.dataset["formsRun"]||'');element.addEventListener('click',function(){return container.path(action)();});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-select-all",controller:function(element){let select=document.createElement("button");let unselect=document.createElement("button");select.textContent='Select All';unselect.textContent='Unselect All';select.classList.add('link');select.classList.add('margin-top-tiny');select.classList.add('margin-start-small');select.classList.add('text-size-small');select.classList.add('pull-end');unselect.classList.add('link');unselect.classList.add('margin-top-tiny');unselect.classList.add('margin-start-small');unselect.classList.add('text-size-small');unselect.classList.add('pull-end');select.type='button';unselect.type='button';element.parentNode.insertBefore(select,element);element.parentNode.insertBefore(unselect,element);select.addEventListener('click',function(){let checkboxes=element.querySelectorAll("input[type='checkbox']");for(var i=0;i<checkboxes.length;i++){checkboxes[i].checked=true;checkboxes[i].dispatchEvent(new Event('change'));}})
unselect.addEventListener('click',function(){let checkboxes=element.querySelectorAll("input[type='checkbox']");for(var i=0;i<checkboxes.length;i++){checkboxes[i].checked=false;checkboxes[i].dispatchEvent(new Event('change'));}})}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-show-secret",controller:function(element,document){let button=document.createElement('span');button.className="link pull-end text-size-small margin-top-negative icon-eye";button.innerHTML=(element.type=='password')?'Show Secret':'Hide Secret';button.style.visibility=(element.value=='')?'hidden':'visible';element.insertAdjacentElement("beforebegin",button);button.addEventListener("click",function(event){switch(element.type){case"password":element.type="text";button.innerHTML='Hide Secret';break;case"text":element.type="password";button.innerHTML='Show Secret';break;default:console.warn("data-forms-show-secret: element.type NOT text NOR password");}});let sync=function(event){button.style.visibility=(element.value=='')?'hidden':'visible';};element.addEventListener("keyup",sync);element.addEventListener("change",sync);},});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-switch",controller:function(element){let input=window.document.createElement("input");input.type="checkbox";input.className="button switch";let syncA=function(){let value=input.checked?"true":"false"
unselect.addEventListener('click',function(){let checkboxes=element.querySelectorAll("input[type='checkbox']");for(var i=0;i<checkboxes.length;i++){checkboxes[i].checked=false;checkboxes[i].dispatchEvent(new Event('change'));}})}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-show-secret",controller:function(element,document){let button=document.createElement('span');button.className="link pull-end text-size-small margin-top-negative icon-eye";button.innerHTML=(element.type=='password')?'Show Secret':'Hide Secret';button.style.visibility=(element.value=='')?'hidden':'visible';element.insertAdjacentElement("beforebegin",button);button.addEventListener("click",function(event){switch(element.type){case"password":element.type="text";button.innerHTML='Hide Secret';break;case"text":element.type="password";button.innerHTML='Show Secret';break;default:console.warn("data-forms-show-secret: element.type NOT text NOR password");}});let sync=function(event){button.style.visibility=(element.value=='')?'hidden':'visible';};element.addEventListener("keyup",sync);element.addEventListener("change",sync);},});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-switch",controller:function(element){let input=window.document.createElement("input");input.type="checkbox";input.className="button switch "+element.className;let syncA=function(){let value=input.checked?"true":"false"
let old=element.value;element.value=value;if(value!==old){element.dispatchEvent(new Event('change'));}};let syncB=function(){input.checked=(element.value==="true");};input.addEventListener("input",syncA);input.addEventListener("change",syncA);element.addEventListener("input",syncB);element.addEventListener("change",syncB);syncA();element.parentNode.insertBefore(input,element);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-tags",controller:function(element){let array=[];let tags=window.document.createElement("div");let preview=window.document.createElement("ul");let add=window.document.createElement("input");let listen=function(event){if((event.key==="Enter"||event.key===" "||event.key==="Tab")&&add.value.length>0){array.push(add.value);add.value="";element.value=JSON.stringify(array);check();if(event.key!=="Tab"){event.preventDefault();}}
if((event.key==="Backspace"||event.key==="Delete")&&add.value===""){array.splice(-1,1);element.value=JSON.stringify(array);check();}
return false;};let check=function(){try{array=JSON.parse(element.value)||[];}catch(error){array=[];}

View file

@ -27,7 +27,7 @@ return http.post(path,{'content-type':'application/json',},payload);},delete:fun
if(password===undefined){throw new Error('Missing required parameter: "password"');}
let path='/account/email';let payload={};if(email){payload['email']=email;}
if(password){payload['password']=password;}
return http.patch(path,{'content-type':'application/json',},payload);},createJWT:function(){let path='/account/jwt';let payload={};return http.post(path,{'content-type':'application/json',},payload);},getLogs:function(){let path='/account/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},updateName:function(name){if(name===undefined){throw new Error('Missing required parameter: "name"');}
return http.patch(path,{'content-type':'application/json',},payload);},getLogs:function(){let path='/account/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},updateName:function(name){if(name===undefined){throw new Error('Missing required parameter: "name"');}
let path='/account/name';let payload={};if(name){payload['name']=name;}
return http.patch(path,{'content-type':'application/json',},payload);},updatePassword:function(password,oldPassword){if(password===undefined){throw new Error('Missing required parameter: "password"');}
if(oldPassword===undefined){throw new Error('Missing required parameter: "oldPassword"');}
@ -244,7 +244,14 @@ if(legalTaxId){payload['legalTaxId']=legalTaxId;}
return http.patch(path,{'content-type':'application/json',},payload);},delete:function(projectId,password){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(password===undefined){throw new Error('Missing required parameter: "password"');}
let path='/projects/{projectId}'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(password){payload['password']=password;}
return http.delete(path,{'content-type':'application/json',},payload);},listDomains:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
return http.delete(path,{'content-type':'application/json',},payload);},updateAuthLimit:function(projectId,limit){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(limit===undefined){throw new Error('Missing required parameter: "limit"');}
let path='/projects/{projectId}/auth/limit'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(typeof limit!=='undefined'){payload['limit']=limit;}
return http.patch(path,{'content-type':'application/json',},payload);},updateAuthStatus:function(projectId,method,status){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(method===undefined){throw new Error('Missing required parameter: "method"');}
if(status===undefined){throw new Error('Missing required parameter: "status"');}
let path='/projects/{projectId}/auth/{method}'.replace(new RegExp('{projectId}','g'),projectId).replace(new RegExp('{method}','g'),method);let payload={};if(status){payload['status']=status;}
return http.patch(path,{'content-type':'application/json',},payload);},listDomains:function(projectId){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/domains'.replace(new RegExp('{projectId}','g'),projectId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},createDomain:function(projectId,domain){if(projectId===undefined){throw new Error('Missing required parameter: "projectId"');}
if(domain===undefined){throw new Error('Missing required parameter: "domain"');}
let path='/projects/{projectId}/domains'.replace(new RegExp('{projectId}','g'),projectId);let payload={};if(domain){payload['domain']=domain;}

View file

@ -256,9 +256,11 @@ match=text.match(new RegExp(regex,'gi'))
if(!match){return fail}
for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}}
return(date.getTime()/1000)}
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){if(value&&Array.isArray(value)&&to!=='array'){value=value.map(element=>cast(element,to));return value;}
switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return value;}
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if(name.startsWith('[')){let splitName=name.split('.');if(splitName.length>1&&splitName[0].endsWith(']')){name=splitName[splitName.length-1];}}
if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}
ref=json[name];}
else{if(!Array.isArray(json[name])){json[name]=[];}
json[name].push({});ref=json[name][json[name].length-1];}}
@ -304,9 +306,9 @@ return result.length;}).add("documentAction",function(container){let collection=
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
return'';}).add("firstElement",function($value){if($value&&$value[0]){return $value[0];}
return $value;}).add("platformsLimit",function($value){return $value;}).add("limit",function($value){let postfix=($value.length>=50)?'...':'';return $value.substring(0,50)+postfix;;}).add("arraySentence",function($value){if(!Array.isArray($value)){return'';}
return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("envName",function($value,env){if(env&&env.ENVIRONMENTS&&env.ENVIRONMENTS[$value]){return env.ENVIRONMENTS[$value].name;}
return'';}).add("envLogo",function($value,env){if(env&&env.ENVIRONMENTS&&env.ENVIRONMENTS[$value]){return env.ENVIRONMENTS[$value].logo;}
return'';}).add("envVersion",function($value,env){if(env&&env.ENVIRONMENTS&&env.ENVIRONMENTS[$value]){return env.ENVIRONMENTS[$value].version;}
return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("envName",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].name;}
return'';}).add("envLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].logo;}
return'';}).add("envVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;}
return'';});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);}
@ -326,8 +328,8 @@ if(element.array){document[element.key]=[];}}}}}};let getParams=function getPara
while((match=REGEX_PARAMETERS_VALUES.exec(functionAsString))){params.push(match[1]);}
return params;};let getValue=function(key,prefix,data){let result=null;if(!key){return null;}
let attrKey=prefix+key.charAt(0).toUpperCase()+key.slice(1);if(element.dataset[attrKey]){result=expression.parse(element.dataset[attrKey]);if(element.dataset[attrKey+"CastTo"]==="array"){result=result.split(",");}}
if(data[key]){result=data[key];}
if(!result){result="";}
if(typeof data[key]!=='undefined'){result=data[key];}
if(typeof result==='undefined'){result="";}
return result;};let resolve=function(target,prefix="param",data={}){if(!target){return function(){};}
let args=getParams(target);return target.apply(target,args.map(function(value){let result=getValue(value,prefix,data);return result;}));};let exec=function(event){let parsedSuccess=expression.parse(success);let parsedFailure=expression.parse(failure);let parsedAction=expression.parse(action);parsedSuccess=parsedSuccess&&parsedSuccess!=""?parsedSuccess.split(",").map(element=>element.trim()):[];parsedFailure=parsedFailure&&parsedFailure!=""?parsedFailure.split(",").map(element=>element.trim()):[];element.$lsSkip=true;element.classList.add("load-service-start");if(!document.body.contains(element)){element=undefined;return false;}
if(event){event.preventDefault();}
@ -392,7 +394,7 @@ score+=(variationCount-1)*10;return parseInt(score);};var callback=function(){va
if(rtl.isRTL(content)){paragraph.style.direction='rtl';paragraph.style.textAlign='right';}
else{paragraph.style.direction='ltr';paragraph.style.textAlign='left';}
last=paragraph;}};var santize=function(e){clean(e);alignText(e);};element.addEventListener("change",function(){editor.content.innerHTML=markdown.render(element.value);alignText();});editor.content.setAttribute("placeholder",element.placeholder);editor.content.innerHTML=markdown.render(element.value);editor.content.tabIndex=0;alignText();editor.content.onkeydown=function preventTab(event){if(event.which===9){event.preventDefault();if(document.activeElement){var focussable=Array.prototype.filter.call(document.querySelectorAll('a:not([disabled]), button:not([disabled]), select:not([disabled]), input[type=text]:not([disabled]), input[type=checkbox]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])'),function(element){return(element.offsetWidth>0||element.offsetHeight>0||element===document.activeElement);});var index=focussable.indexOf(document.activeElement);if(index>-1){if(event.shiftKey){var prevElement=focussable[index-1]||focussable[focussable.length-1];prevElement.focus();}else{var nextElement=focussable[index+1]||focussable[0];nextElement.focus();}}}}};div.addEventListener("paste",santize);div.addEventListener("drop",santize);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-remove",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-remove]")).map(function(obj){obj.addEventListener("click",function(){element.parentNode.removeChild(element);});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-run",repeat:false,controller:function(element,expression,container){let action=expression.parse(element.dataset["formsRun"]||'');element.addEventListener('click',function(){return container.path(action)();});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-select-all",controller:function(element){let select=document.createElement("button");let unselect=document.createElement("button");select.textContent='Select All';unselect.textContent='Unselect All';select.classList.add('link');select.classList.add('margin-top-tiny');select.classList.add('margin-start-small');select.classList.add('text-size-small');select.classList.add('pull-end');unselect.classList.add('link');unselect.classList.add('margin-top-tiny');unselect.classList.add('margin-start-small');unselect.classList.add('text-size-small');unselect.classList.add('pull-end');select.type='button';unselect.type='button';element.parentNode.insertBefore(select,element);element.parentNode.insertBefore(unselect,element);select.addEventListener('click',function(){let checkboxes=element.querySelectorAll("input[type='checkbox']");for(var i=0;i<checkboxes.length;i++){checkboxes[i].checked=true;checkboxes[i].dispatchEvent(new Event('change'));}})
unselect.addEventListener('click',function(){let checkboxes=element.querySelectorAll("input[type='checkbox']");for(var i=0;i<checkboxes.length;i++){checkboxes[i].checked=false;checkboxes[i].dispatchEvent(new Event('change'));}})}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-show-secret",controller:function(element,document){let button=document.createElement('span');button.className="link pull-end text-size-small margin-top-negative icon-eye";button.innerHTML=(element.type=='password')?'Show Secret':'Hide Secret';button.style.visibility=(element.value=='')?'hidden':'visible';element.insertAdjacentElement("beforebegin",button);button.addEventListener("click",function(event){switch(element.type){case"password":element.type="text";button.innerHTML='Hide Secret';break;case"text":element.type="password";button.innerHTML='Show Secret';break;default:console.warn("data-forms-show-secret: element.type NOT text NOR password");}});let sync=function(event){button.style.visibility=(element.value=='')?'hidden':'visible';};element.addEventListener("keyup",sync);element.addEventListener("change",sync);},});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-switch",controller:function(element){let input=window.document.createElement("input");input.type="checkbox";input.className="button switch";let syncA=function(){let value=input.checked?"true":"false"
unselect.addEventListener('click',function(){let checkboxes=element.querySelectorAll("input[type='checkbox']");for(var i=0;i<checkboxes.length;i++){checkboxes[i].checked=false;checkboxes[i].dispatchEvent(new Event('change'));}})}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-show-secret",controller:function(element,document){let button=document.createElement('span');button.className="link pull-end text-size-small margin-top-negative icon-eye";button.innerHTML=(element.type=='password')?'Show Secret':'Hide Secret';button.style.visibility=(element.value=='')?'hidden':'visible';element.insertAdjacentElement("beforebegin",button);button.addEventListener("click",function(event){switch(element.type){case"password":element.type="text";button.innerHTML='Hide Secret';break;case"text":element.type="password";button.innerHTML='Show Secret';break;default:console.warn("data-forms-show-secret: element.type NOT text NOR password");}});let sync=function(event){button.style.visibility=(element.value=='')?'hidden':'visible';};element.addEventListener("keyup",sync);element.addEventListener("change",sync);},});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-switch",controller:function(element){let input=window.document.createElement("input");input.type="checkbox";input.className="button switch "+element.className;let syncA=function(){let value=input.checked?"true":"false"
let old=element.value;element.value=value;if(value!==old){element.dispatchEvent(new Event('change'));}};let syncB=function(){input.checked=(element.value==="true");};input.addEventListener("input",syncA);input.addEventListener("change",syncA);element.addEventListener("input",syncB);element.addEventListener("change",syncB);syncA();element.parentNode.insertBefore(input,element);}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-tags",controller:function(element){let array=[];let tags=window.document.createElement("div");let preview=window.document.createElement("ul");let add=window.document.createElement("input");let listen=function(event){if((event.key==="Enter"||event.key===" "||event.key==="Tab")&&add.value.length>0){array.push(add.value);add.value="";element.value=JSON.stringify(array);check();if(event.key!=="Tab"){event.preventDefault();}}
if((event.key==="Backspace"||event.key==="Delete")&&add.value===""){array.splice(-1,1);element.value=JSON.stringify(array);check();}
return false;};let check=function(){try{array=JSON.parse(element.value)||[];}catch(error){array=[];}

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View file

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
public/images/users/jwt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

View file

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

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