1
0
Fork 0
mirror of synced 2024-06-18 18:54:55 +12:00

Merge branch 'feat-database-indexing' of https://github.com/appwrite/appwrite into feat-database-indexing

This commit is contained in:
Torsten Dittmann 2022-01-04 17:04:26 +01:00
commit f888a697d4
31 changed files with 889 additions and 74 deletions

View file

@ -2,7 +2,6 @@ dist: focal
arch:
- amd64
- arm64-graviton2
os: linux
@ -54,16 +53,16 @@ install:
- docker pull php:8.0-cli-alpine
- docker-compose build
- docker-compose up -d
- sleep 10
- sleep 60
script:
- docker ps -a
# Tests should fail if any container is in exited status
- ALL_UP=`docker ps -aq --filter "status=exited"`
- >
if [[ "$ALL_UP" != "" ]]; then
exit 1
fi
# - ALL_UP=`docker ps -aq --filter "status=exited"`
# - >
# if [[ "$ALL_UP" != "" ]]; then
# exit 1
# fi
- docker-compose logs appwrite
- docker-compose logs appwrite-realtime
- docker-compose logs mariadb

View file

@ -295,6 +295,16 @@ For generating a new console SDK follow the next steps:
5. Copy `iife/sdk.js` to `appwrite.js`
6. Go back to the root of the project `run npm run build`
## Checklist for Releasing SDKs
Things to remember when releasing SDKs
* Update the Changelogs in **docs/sdks** (right now only Dart and Flutter are using these)
* Update **GETTING_STARTED.md** in **docs/sdks** for each SDKs if any changes in the related APIs in there
* Update SDK versions as required on **app/config/platforms.php**
* Generate SDKs using the command `php app/cli.php sdks` and follow the instructions
* Release new tags on GitHub repository for each SDKs
## Debug
Appwrite uses [yasd](https://github.com/swoole/yasd) debugger, which can be made available during build of Appwrite. You can connect to the debugger using VS Code [PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) extension or if you are in PHP Storm you don't need any plugin. Below are the settings required for remote debugger connection.

View file

@ -998,7 +998,7 @@ $collections = [
'$id' => 'prefs',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'size' => 65535,
'signed' => true,
'required' => false,
'default' => new \stdClass(),

View file

@ -55,7 +55,7 @@ App::post('/v1/account')
->inject('audits')
->inject('usage')
->action(function ($userId, $email, $password, $name, $request, $response, $project, $dbForProject, $audits, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
@ -155,7 +155,7 @@ App::post('/v1/account/sessions')
->inject('audits')
->inject('usage')
->action(function ($email, $password, $request, $response, $dbForProject, $locale, $geodb, $audits, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
@ -267,7 +267,7 @@ App::get('/v1/account/sessions/oauth2/:provider')
->inject('response')
->inject('project')
->action(function ($provider, $success, $failure, $scopes, $request, $response, $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
@ -320,7 +320,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
->inject('request')
->inject('response')
->action(function ($projectId, $provider, $code, $state, $request, $response) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
$domain = $request->getHostname();
@ -347,7 +347,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
->inject('request')
->inject('response')
->action(function ($projectId, $provider, $code, $state, $request, $response) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
$domain = $request->getHostname();
@ -382,7 +382,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
->inject('events')
->inject('usage')
->action(function ($provider, $code, $state, $request, $response, $project, $user, $dbForProject, $geodb, $audits, $events, $usage) use ($oauthDefaultSuccess) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Document $user */
@ -627,7 +627,7 @@ App::post('/v1/account/sessions/magic-url')
->inject('events')
->inject('mails')
->action(function ($userId, $email, $url, $request, $response, $project, $dbForProject, $locale, $audits, $events, $mails) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
@ -773,7 +773,7 @@ App::put('/v1/account/sessions/magic-url')
->action(function ($userId, $secret, $request, $response, $dbForProject, $locale, $geodb, $audits) {
/** @var string $userId */
/** @var string $secret */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
@ -899,7 +899,7 @@ App::post('/v1/account/sessions/anonymous')
->inject('audits')
->inject('usage')
->action(function ($request, $response, $locale, $user, $project, $dbForProject, $geodb, $audits, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
/** @var Utopia\Database\Document $user */
@ -1512,7 +1512,7 @@ App::delete('/v1/account')
->inject('events')
->inject('usage')
->action(function ($request, $response, $user, $dbForProject, $audits, $events, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
@ -1582,7 +1582,7 @@ App::delete('/v1/account/sessions/:sessionId')
->inject('events')
->inject('usage')
->action(function ($sessionId, $request, $response, $user, $dbForProject, $locale, $audits, $events, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
@ -1668,7 +1668,7 @@ App::delete('/v1/account/sessions')
->inject('events')
->inject('usage')
->action(function ($request, $response, $user, $dbForProject, $locale, $audits, $events, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
@ -1753,7 +1753,7 @@ App::post('/v1/account/recovery')
->inject('events')
->inject('usage')
->action(function ($email, $url, $request, $response, $dbForProject, $project, $locale, $mails, $audits, $events, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
@ -1945,7 +1945,7 @@ App::post('/v1/account/verification')
->inject('mails')
->inject('usage')
->action(function ($url, $request, $response, $project, $user, $dbForProject, $locale, $audits, $events, $mails, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Document $user */

View file

@ -453,7 +453,7 @@ App::post('/v1/functions/:functionId/tags')
->inject('dbForProject')
->inject('usage')
->action(function ($functionId, $command, $file, $request, $response, $dbForProject, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $usage */

View file

@ -21,7 +21,7 @@ App::get('/v1/locale')
->inject('locale')
->inject('geodb')
->action(function ($request, $response, $locale, $geodb) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */

View file

@ -52,7 +52,7 @@ App::post('/v1/storage/files')
->inject('audits')
->inject('usage')
->action(function ($fileId, $file, $read, $write, $request, $response, $dbForProject, $user, $audits, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $user */
@ -295,7 +295,7 @@ App::get('/v1/storage/files/:fileId/preview')
->inject('dbForProject')
->inject('usage')
->action(function ($fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForProject, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */

View file

@ -541,7 +541,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
->inject('dbForProject')
->inject('audits')
->action(function ($teamId, $membershipId, $roles, $request, $response, $user, $dbForProject, $audits) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
@ -608,7 +608,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
->inject('geodb')
->inject('audits')
->action(function ($teamId, $membershipId, $userId, $secret, $request, $response, $user, $dbForProject, $geodb, $audits) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */

View file

@ -5,7 +5,7 @@ require_once __DIR__.'/../init.php';
use Utopia\App;
use Utopia\Logger\Log;
use Utopia\Logger\Log\User;
use Utopia\Swoole\Request;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\View;
use Utopia\Exception;
@ -16,10 +16,12 @@ use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Response\Filters\V06;
use Appwrite\Utopia\Response\Filters\V07;
use Appwrite\Utopia\Response\Filters\V08;
use Appwrite\Utopia\Response\Filters\V11;
use Utopia\CLI\Console;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Appwrite\Utopia\Request\Filters\V12;
Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
@ -27,7 +29,7 @@ Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
App::init(function ($utopia, $request, $response, $console, $project, $dbForConsole, $user, $locale, $clients) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $console */
/** @var Utopia\Database\Document $project */
@ -36,6 +38,25 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
/** @var Utopia\Locale\Locale $locale */
/** @var array $clients */
/*
* Request format
*/
$route = $utopia->match($request);
Request::setRoute($route);
$requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
if ($requestFormat) {
switch($requestFormat) {
case version_compare ($requestFormat , '0.12.0', '<') :
Request::setFilter(new V12());
break;
default:
Request::setFilter(null);
}
} else {
Request::setFilter(null);
}
$domain = $request->getHostname();
$domains = Config::getParam('domains', []);
if (!array_key_exists($domain, $domains)) {
@ -82,12 +103,9 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
}
$localeParam = (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', ''));
if (\in_array($localeParam, Config::getParam('locale-codes'))) {
$locale->setDefault($localeParam);
};
$route = $utopia->match($request);
}
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
@ -149,6 +167,8 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
break;
case version_compare ($responseFormat , '0.8.0', '<=') :
Response::setFilter(new V08());
case version_compare ($responseFormat , '0.11.0', '<=') :
Response::setFilter(new V11());
break;
default:
Response::setFilter(null);
@ -285,7 +305,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
}, ['utopia', 'request', 'response', 'console', 'project', 'dbForConsole', 'user', 'locale', 'clients']);
App::options(function ($request, $response) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
$origin = $request->getOrigin();
@ -303,7 +323,7 @@ App::options(function ($request, $response) {
App::error(function ($error, $utopia, $request, $response, $layout, $project, $logger, $loggerBreadcrumbs) {
/** @var Exception $error */
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Utopia\View $layout */
/** @var Utopia\Database\Document $project */

View file

@ -205,7 +205,7 @@ App::get('/v1/mock/tests/general/download')
->label('sdk.mock', true)
->inject('response')
->action(function ($response) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
$response
->setContentType('text/plain')
@ -236,7 +236,7 @@ App::post('/v1/mock/tests/general/upload')
->inject('request')
->inject('response')
->action(function ($x, $y, $z, $file, $request, $response) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Utopia\Swoole\Response $response */
$file = $request->getFiles('file');
@ -373,7 +373,7 @@ App::get('/v1/mock/tests/general/get-cookie')
->label('sdk.mock', true)
->inject('request')
->action(function ($request) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
if ($request->getCookie('cookieName', '') !== 'cookieValue') {
throw new Exception('Missing cookie value', 400);
@ -551,7 +551,7 @@ App::get('/v1/mock/tests/general/oauth2/failure')
App::shutdown(function($utopia, $response, $request) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
$result = [];

View file

@ -13,7 +13,7 @@ use Utopia\Storage\Storage;
App::init(function ($utopia, $request, $response, $project, $user, $events, $audits, $usage, $deletes, $database, $dbForProject, $mode) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Document $user */
@ -134,7 +134,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
App::init(function ($utopia, $request, $project) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Utopia\Database\Document $project */
$route = $utopia->match($request);
@ -187,7 +187,7 @@ App::init(function ($utopia, $request, $project) {
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $database, $mode) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Appwrite\Event\Event $events */

View file

@ -5,7 +5,7 @@ use Utopia\Config\Config;
App::init(function ($utopia, $request, $response, $layout) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Utopia\View $layout */

View file

@ -15,7 +15,7 @@ use Utopia\Audit\Audit;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Database\Document;
use Utopia\Swoole\Files;
use Utopia\Swoole\Request;
use Appwrite\Utopia\Request;
use Utopia\Logger\Log;
use Utopia\Logger\Log\User;

View file

@ -664,7 +664,7 @@ App::setResource('clients', function ($request, $console, $project) {
}, ['request', 'console', 'project']);
App::setResource('user', function($mode, $project, $console, $request, $response, $dbForProject, $dbForConsole) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
@ -748,7 +748,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForConsole']);
App::setResource('project', function($dbForConsole, $request, $console) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/** @var Utopia\Database\Database $dbForConsole */
/** @var Utopia\Database\Document $console */
@ -828,7 +828,7 @@ App::setResource('dbForConsole', function($db, $cache) {
}, ['db', 'cache']);
App::setResource('mode', function($request) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Request $request */
/**
* Defines the mode for the request:

View file

@ -23,7 +23,7 @@ use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Registry\Registry;
use Utopia\Swoole\Request;
use Appwrite\Utopia\Request;
use Utopia\WebSocket\Server;
use Utopia\WebSocket\Adapter;

View file

@ -38,7 +38,7 @@
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.6.*",
"utopia-php/framework": "0.19.*",
"utopia-php/framework": "0.19.5",
"utopia-php/logger": "0.1.*",
"utopia-php/abuse": "0.7.*",
"utopia-php/analytics": "0.2.*",
@ -66,7 +66,6 @@
"adhocore/jwt": "1.1.2",
"slickdeals/statsd": "3.1.0"
},
"repositories": [],
"require-dev": {
"appwrite/sdk-generator": "0.17.0",
"phpunit/phpunit": "9.5.10",

14
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c602e99a298c00b57253651a3108a6df",
"content-hash": "d0df4734e38f660ce979011d70155357",
"packages": [
{
"name": "adhocore/jwt",
@ -2255,16 +2255,16 @@
},
{
"name": "utopia-php/framework",
"version": "0.19.4",
"version": "0.19.5",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/framework.git",
"reference": "b1c79f199a6adbf8526cea272d931213a8eb511d"
"reference": "1c28ba9a5b491cf7c90c535fefee5832c7133623"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/b1c79f199a6adbf8526cea272d931213a8eb511d",
"reference": "b1c79f199a6adbf8526cea272d931213a8eb511d",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/1c28ba9a5b491cf7c90c535fefee5832c7133623",
"reference": "1c28ba9a5b491cf7c90c535fefee5832c7133623",
"shasum": ""
},
"require": {
@ -2298,9 +2298,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/framework/issues",
"source": "https://github.com/utopia-php/framework/tree/0.19.4"
"source": "https://github.com/utopia-php/framework/tree/0.19.5"
},
"time": "2021-12-29T15:05:19+00:00"
"time": "2022-01-04T14:40:23+00:00"
},
{
"name": "utopia-php/image",

View file

@ -1 +1 @@
Update currently logged in user account preferences. You can pass only the specific settings you wish to update.
Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.

View file

@ -1 +1 @@
Update the user preferences by its unique ID. You can pass only the specific settings you wish to update.
Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.

View file

@ -0,0 +1,128 @@
<?php
namespace Appwrite\Utopia;
use Appwrite\Utopia\Request\Filter;
use Swoole\Http\Request as SwooleRequest;
use Utopia\Route;
use Utopia\Swoole\Request as UtopiaRequest;
class Request extends UtopiaRequest
{
/**
* @var Filter
*/
private static $filter = null;
/**
* @var Route
*/
private static $route = null;
/**
* Request constructor.
*/
public function __construct(SwooleRequest $request)
{
parent::__construct($request);
}
/**
* Get Params
*
* Get all params of current method
*
* @return array
*/
public function getParams(): array
{
$requestParameters = [];
switch($this->getMethod()) {
case self::METHOD_GET:
$requestParameters = (!empty($this->swoole->get)) ? $this->swoole->get : [];
break;
case self::METHOD_POST:
case self::METHOD_PUT:
case self::METHOD_PATCH:
case self::METHOD_DELETE:
$requestParameters = $this->generateInput();
break;
default:
$requestParameters = (!empty($this->swoole->get)) ? $this->swoole->get : [];
}
if (self::hasFilter() && self::hasRoute()) {
$endpointIdentifier = self::getRoute()->getLabel('sdk.namespace', 'unknown') . '.' . self::getRoute()->getLabel('sdk.method', 'unknown');
$requestParameters = self::getFilter()->parse($requestParameters, $endpointIdentifier);
}
return $requestParameters;
}
/**
* Function to set a response filter
*
* @param $filter the response filter to set
*
* @return void
*/
public static function setFilter(?Filter $filter)
{
self::$filter = $filter;
}
/**
* Return the currently set filter
*
* @return Filter
*/
public static function getFilter(): ?Filter
{
return self::$filter;
}
/**
* Check if a filter has been set
*
* @return bool
*/
public static function hasFilter(): bool
{
return self::$filter != null;
}
/**
* Function to set a request route
*
* @param Route $route the request route to set
*
* @return void
*/
public static function setRoute(?Route $route)
{
self::$route = $route;
}
/**
* Return the currently get route
*
* @return Route
*/
public static function getRoute(): ?Route
{
return self::$route;
}
/**
* Check if a route has been set
*
* @return bool
*/
public static function hasRoute(): bool
{
return self::$route != null;
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace Appwrite\Utopia\Request;
abstract class Filter
{
/**
* Parse params to another format.
*
* @param array $content
* @param string $model
*
* @return array
*/
abstract public function parse(array $content, string $model): array;
}

View file

@ -0,0 +1,160 @@
<?php
namespace Appwrite\Utopia\Request\Filters;
use Appwrite\Utopia\Request\Filter;
class V12 extends Filter
{
// Convert 0.11 params format to 0.12 format
public function parse(array $content, string $model): array
{
switch ($model) {
// No IDs -> Custom IDs
case "account.create":
case "account.createMagicURLSession":
case "users.create":
$content = $this->addId($content, 'userId');
break;
case "functions.create":
$content = $this->addId($content, 'functionId');
break;
case "teams.create":
$content = $this->addId($content, 'teamId');
break;
// Status integer -> boolean
case "users.updateStatus":
$content = $this->convertStatus($content);
break;
// Deprecating order type
case "functions.listExecutions":
$content = $this->removeOrderType($content);
break;
// The rest (more complex) formats
case "database.createDocument":
$content = $this->addId($content, 'documentId');
$content = $this->removeParentProperties($content);
break;
case "database.listDocuments":
$content = $this->removeOrderCast($content);
$content = $this->convertOrder($content);
$content = $this->convertQueries($content);
break;
case "database.createCollection":
$content = $this->addId($content, 'collectionId');
$content = $this->removeRules($content);
$content = $this->addCollectionPermissionLevel($content);
break;
case "database.updateCollection":
$content = $this->removeRules($content);
$content = $this->addCollectionPermissionLevel($content);
break;
}
return $content;
}
// New parameters
protected function addId(array $content, string $key): array
{
$content[$key] = 'unique()';
return $content;
}
protected function addCollectionPermissionLevel(array $content): array
{
$content['permission'] = 'document';
return $content;
}
// Deprecated parameters
protected function removeRules(array $content): array
{
unset($content['rules']);
return $content;
}
protected function removeOrderType(array $content): array
{
unset($content['orderType']);
return $content;
}
protected function removeOrderCast(array $content): array
{
unset($content['orderCast']);
return $content;
}
protected function removeParentProperties(array $content): array
{
if (isset($content['parentDocument'])) unset($content['parentDocument']);
if (isset($content['parentProperty'])) unset($content['parentProperty']);
if (isset($content['parentPropertyType'])) unset($content['parentPropertyType']);
return $content;
}
// Modified parameters
protected function convertStatus(array $content): array
{
if (isset($content['status'])) {
$content['status'] = $content['status'] === 2 ? false : true;
}
return $content;
}
protected function convertOrder(array $content): array
{
if (isset($content['orderField'])) {
$content['orderAttributes'] = [ $content['orderField'] ];
unset($content['orderField']);
}
if (isset($content['orderType'])) {
$content['orderTypes'] = [ $content['orderType'] ];
unset($content['orderType']);
}
return $content;
}
protected function convertQueries(array $content): array
{
$queries = [];
if(!empty($content['filters'])) {
foreach ($content['filters'] as $filter) {
$operators = ['=' => 'equal', '!=' => 'notEqual', '>' => 'greater', '<' => 'lesser', '<=' => 'lesserEqual', '>=' => 'greaterEqual'];
foreach ($operators as $operator => $operatorVerbose) {
if (\str_contains($filter, $operator)) {
$usedOperator = $operator;
break;
}
}
if(isset($usedOperator)) {
[ $attributeKey, $filterValue ] = \explode($usedOperator, $filter);
$filterValue = \is_numeric($filterValue) ? $filterValue : '"' . $filterValue . '"';
$query = $attributeKey . '.' . $operators[$usedOperator] . '(' . $filterValue . ')';
\array_push($queries, $query);
}
}
}
// We cannot migrate search properly
unset($content['search']);
unset($content['filters']);
unset($content['search']);
$content['queries'] = $queries;
return $content;
}
}

View file

@ -349,7 +349,7 @@ class Response extends SwooleResponse
$output = $this->output($document, $model);
// If filter is set, parse the output
if (self::isFilter()) {
if (self::hasFilter()) {
$output = self::getFilter()->parse($output, $model);
}
@ -488,7 +488,7 @@ class Response extends SwooleResponse
*
* @return bool
*/
public static function isFilter(): bool
public static function hasFilter(): bool
{
return self::$filter != null;
}

View file

@ -0,0 +1,402 @@
<?php
namespace Appwrite\Utopia\Response\Filters;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Filter;
use Exception;
class V11 extends Filter
{
// Convert 0.12 Data format to 0.11 format
public function parse(array $content, string $model): array
{
$parsedResponse = $content;
switch ($model) {
// Update permissions
case Response::MODEL_DOCUMENT:
$parsedResponse = $this->parsePermissions($content);
break;
case Response::MODEL_DOCUMENT_LIST:
$parsedResponse = $this->parseDocumentList($content);
break;
case Response::MODEL_FILE:
$parsedResponse = $this->parsePermissions($content);
break;
case Response::MODEL_FILE_LIST:
$parsedResponse = $this->parseFileList($content);
break;
case Response::MODEL_EXECUTION:
$parsedResponse = $this->parseExecutionPermissions($content);
break;
case Response::MODEL_EXECUTION_LIST:
$parsedResponse = $this->parseExecutionsList($content);
break;
case Response::MODEL_FUNCTION:
$parsedResponse = $this->parseFunctionPermissions($content);
break;
case Response::MODEL_FUNCTION_LIST:
$parsedResponse = $this->parseFunctionsList($content);
break;
// Convert status from boolean to int
case Response::MODEL_USER:
$parsedResponse = $this->parseStatus($content);
break;
case Response::MODEL_USER_LIST:
$parsedResponse = $this->parseUserList($content);
break;
// Convert all Health responses back to original
case Response::MODEL_HEALTH_STATUS:
$parsedResponse = $this->parseHealthStatus($content);
break;
case Response::MODEL_HEALTH_VERSION:
$parsedResponse = $this->parseHealthVersion($content);
break;
case Response::MODEL_HEALTH_TIME:
$parsedResponse = $this->parseHealthTime($content);
break;
case Response::MODEL_HEALTH_QUEUE:
$parsedResponse = $this->parseHealthQueue($content);
break;
case Response::MODEL_HEALTH_ANTIVIRUS:
$parsedResponse = $this->parseHealthAntivirus($content);
break;
// Complex filters
case Response::MODEL_COLLECTION:
$parsedResponse = $this->parseCollection($content);
break;
case Response::MODEL_COLLECTION_LIST:
$parsedResponse = $this->parseCollectionList($content);
break;
case Response::MODEL_LOG:
$parsedResponse = $this->parseLog($content);
break;
case Response::MODEL_LOG_LIST:
$parsedResponse = $this->parseLogList($content);
break;
case Response::MODEL_PROJECT:
$parsedResponse = $this->parseProject($content);
break;
case Response::MODEL_PROJECT_LIST:
$parsedResponse = $this->parseProjectList($content);
break;
}
return $parsedResponse;
}
protected function parseDocumentList(array $content)
{
$documents = $content['documents'];
$parsedResponse = [];
foreach ($documents as $document) {
$parsedResponse[] = $this->parsePermissions($document);
}
$content['documents'] = $parsedResponse;
return $content;
}
protected function parseFileList(array $content)
{
$files = $content['files'];
$parsedResponse = [];
foreach ($files as $file) {
$parsedResponse[] = $this->parsePermissions($file);
}
$content['files'] = $parsedResponse;
return $content;
}
protected function parseExecutionsList(array $content)
{
$executions = $content['executions'];
$parsedResponse = [];
foreach ($executions as $execution) {
$parsedResponse[] = $this->parseExecutionPermissions($execution);
}
$content['executions'] = $parsedResponse;
return $content;
}
protected function parseFunctionsList(array $content)
{
$functions = $content['functions'];
$parsedResponse = [];
foreach ($functions as $function) {
$parsedResponse[] = $this->parseFunctionPermissions($function);
}
$content['functions'] = $parsedResponse;
return $content;
}
protected function parseUserList(array $content)
{
$users = $content['users'];
$parsedResponse = [];
foreach ($users as $user) {
$parsedResponse[] = $this->parseStatus($user);
}
$content['users'] = $parsedResponse;
return $content;
}
protected function parseCollection(array $content)
{
$parsedResponse = [];
$parsedResponse = $this->parsePermissions($content);
$parsedResponse = $this->removeRule($content, 'enabled');
$parsedResponse = $this->removeRule($content, 'permission');
$parsedResponse = $this->removeRule($content, 'indexes');
$parsedResponse = $this->removeRule($content, 'enabled');
$parsedResponse = $this->addDate($content, 'dateCreated');
$parsedResponse = $this->addDate($content, 'dateUpdated');
$parsedResponse = $this->parseAttributes($content);
return $parsedResponse;
}
protected function parseCollectionList(array $content)
{
$collections = $content['collections'];
$parsedResponse = [];
foreach ($collections as $collection) {
$parsedResponse[] = $this->parseCollection($collection);
}
$content['collections'] = $parsedResponse;
return $content;
}
protected function parseLog(array $content)
{
$parsedResponse = [];
$parsedResponse = $this->removeRule($content, 'userId');
$parsedResponse = $this->removeRule($content, 'userEmail');
$parsedResponse = $this->removeRule($content, 'userName');
$parsedResponse = $this->removeRule($content, 'mode');
$parsedResponse = $this->removeRule($content, 'sum');
return $parsedResponse;
}
protected function parseLogList(array $content)
{
$logs = $content['logs'];
$parsedResponse = [];
foreach ($logs as $log) {
$parsedResponse[] = $this->parseLog($log);
}
$content['logs'] = $parsedResponse;
return $content;
}
protected function parseProject(array $content)
{
$parsedResponse = [];
$parsedResponse = $this->addTasks($content);
$parsedResponse = $this->parseAuthLimit($content);
$parsedResponse = $this->parseOAuths($content);
$parsedResponse = $this->parseAuthsStatus($content);
$parsedResponse = $this->removeServicesStatus($content);
return $parsedResponse;
}
protected function parseProjectList(array $content)
{
$projects = $content['projects'];
$parsedResponse = [];
foreach ($projects as $project) {
$parsedResponse[] = $this->parseProject($project);
}
$content['projects'] = $parsedResponse;
return $content;
}
protected function parseHealthAntivirus(array $content)
{
if($content['status'] === 'pass') {
$content['status'] = 'online';
}
if($content['status'] === 'fail') {
$content['status'] = 'offline';
}
return $content;
}
protected function parseHealthTime(array $content)
{
$content['remote'] = $content['remoteTime'];
unset($content['remoteTime']);
$content['local'] = $content['localTime'];
unset($content['localTime']);
return $content;
}
protected function parseHealthVersion(array $content)
{
// Did not change
return $content;
}
protected function parseHealthQueue(array $content)
{
// Did not change
return $content;
}
protected function parseHealthStatus(array $content)
{
$content['status'] = 'OK'; // Is always returning pass, was always returning OK
unset($content['ping']);
return $content;
}
protected function parseStatus(array $content)
{
$content['status'] = $content['status'] === true ?
$content['emailVerification'] === true ? 1 : 0
: 2;
return $content;
}
protected function parseAttributes(array $content)
{
$content['rules'] = \array_map(function($attribute) use($content) {
return [
'$id' => $attribute['key'],
'$collection' => $content['$id'],
'type' => $attribute['type'],
'key' => $attribute['key'],
'label' => $attribute['key'],
'default' => $attribute['default'],
'array' => $attribute['array'],
'required' => $attribute['required'],
'list' => $attribute['elements'],
];
}, $content['attributes']);
unset($content['attributes']);
return $content;
}
protected function parseAuthLimit(array $content)
{
$content['usersAuthLimit'] = $content['authLimit'];
unset($content['authLimit']);
return $content;
}
protected function parseOAuths(array $content)
{
$regexPattern = "/provider([a-zA-Z0-9]+)(Appid|Secret)/";
foreach ($content as $key => $value) {
\preg_match_all($regexPattern, $key, $regexGroups);
if(\count($regexGroups[1]) > 0 && \count($regexGroups[2]) > 0) {
$providerName = $regexGroups[1][0];
$valueKey = $regexGroups[2][0];
$content['usersOauth2' . $providerName . $valueKey] = $value;
unset($content['provider' . $providerName . $valueKey]);
}
}
return $content;
}
protected function parseAuthsStatus(array $content)
{
$regexPattern = "/auth([a-zA-Z0-9]+)/";
foreach ($content as $key => $value) {
\preg_match_all($regexPattern, $key, $regexGroups);
if(\count($regexGroups[1]) > 0) {
$providerName = $regexGroups[1][0];
$content[$providerName] = $value;
unset($content['auth' . $providerName]);
}
}
return $content;
}
protected function removeServicesStatus(array $content)
{
// Such a key is part of new response, but is not part of old one. We simply remove it, older version never
// expected it anyway.
foreach ($content as $key => $value) {
if(\str_starts_with($key, 'serviceStatusFor')) {
unset($content[$key]);
}
}
return $content;
}
protected function removeRule(array $content, $key)
{
// Such a key is part of new response, but is not part of old one. We simply remove it, older version never
// expected it anyway.
unset($content[$key]);
return $content;
}
protected function addDate(array $content, $key)
{
// We simply don't have the date available in the content anymore.
// We set it to valid integer that indicates the value is not right
$content[$key] = 0;
return $content;
}
protected function addTasks(array $content)
{
// We simply don't have the date available in the content anymore.
// We set it to valid array
$content['tasks'] = [];
return $content;
}
protected function parsePermissions(array $content)
{
$content['$permissions'] = [ 'read' => $content['$read'], 'write' => $content['$write'] ];
unset($content['$read']);
unset($content['$write']);
return $content;
}
protected function parseFunctionPermissions(array $content)
{
$content['$permissions'] = [ 'execute' => $content['execute'] ];
unset($content['execute']);
return $content;
}
protected function parseExecutionPermissions(array $content)
{
$content['$permissions'] = [ 'read' => $content['$read'] ];
unset($content['$read']);
return $content;
}
}

View file

@ -18,7 +18,7 @@ class HTTPTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_OPTIONS, '/', array_merge([
$response = $this->client->call(Client::METHOD_OPTIONS, '/', \array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
]), []);
@ -38,7 +38,7 @@ class HTTPTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/error', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/error', \array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
]), []);
@ -54,7 +54,7 @@ class HTTPTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/manifest.json', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/manifest.json', \array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
]), []);
@ -73,7 +73,7 @@ class HTTPTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/humans.txt', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/humans.txt', \array_merge([
'origin' => 'http://localhost',
]), []);
@ -86,7 +86,7 @@ class HTTPTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/robots.txt', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/robots.txt', \array_merge([
'origin' => 'http://localhost',
]), []);
@ -165,7 +165,7 @@ class HTTPTest extends Scope
/**
* Test without header
*/
$response = $this->client->call(Client::METHOD_GET, '/locale/continents', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/locale/continents', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
], $this->getHeaders()));
@ -183,7 +183,7 @@ class HTTPTest extends Scope
/**
* Test with header
*/
$response = $this->client->call(Client::METHOD_GET, '/locale/continents', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/locale/continents', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
'x-appwrite-response-format' => '0.6.2'
@ -202,7 +202,7 @@ class HTTPTest extends Scope
/**
* Test without header
*/
$response = $this->client->call(Client::METHOD_GET, '/versions', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/versions', \array_merge([
'content-type' => 'application/json',
], $this->getHeaders()));

View file

@ -46,7 +46,7 @@ abstract class Scope extends TestCase
protected function getLastRequest():array
{
sleep(1);
sleep(5);
$resquest = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
$resquest['data'] = json_decode($resquest['data'], true);

View file

@ -3,6 +3,7 @@
namespace Tests\E2E\Services\Account;
use Tests\E2E\Client;
use function array_merge;
trait AccountBase
{
@ -751,6 +752,36 @@ trait AccountBase
$this->assertEquals($response['headers']['status-code'], 400);
/**
* Prefs size exceeded
*/
$prefsObject = ["longValue" => str_repeat("🍰", 100000)];
$response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
]), [
'prefs' => $prefsObject
]);
$this->assertEquals(400, $response['headers']['status-code']);
// Now let's test the same thing, but with normal symbol instead of multi-byte cake emoji
$prefsObject = ["longValue" => str_repeat("-", 100000)];
$response = $this->client->call(Client::METHOD_PATCH, '/account/prefs', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
]), [
'prefs' => $prefsObject
]);
$this->assertEquals(400, $response['headers']['status-code']);
return $data;
}

View file

@ -158,7 +158,7 @@ class HealthCustomServerTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['size']);
$this->assertLessThan(160, $response['body']['size']);
$this->assertLessThan(200, $response['body']['size']);
/**
* Test for FAILURE

View file

@ -2,6 +2,7 @@
namespace Tests\E2E\Services\Teams;
use Tests\E2E\Client;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\ProjectConsole;
use Tests\E2E\Scopes\SideClient;
@ -12,4 +13,52 @@ class TeamsConsoleClientTest extends Scope
use TeamsBaseClient;
use ProjectConsole;
use SideClient;
public function testRequestHeader() {
/**
* Test without header
*/
$response = $this->client->call(Client::METHOD_POST, '/teams', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'console'
], $this->getHeaders()), [
'name' => 'Latest version Team',
'teamId' => 'unique()'
]);
$this->assertEquals(201, $response['headers']['status-code']);
$team1Id = $response['body']['$id'];
/**
* Test with header
*/
$response = $this->client->call(Client::METHOD_POST, '/teams', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
'x-appwrite-response-format' => '0.11.0'
], $this->getHeaders()), [
'name' => 'Latest version Team'
// Notice "teamId' is not defined
]);
$this->assertEquals(201, $response['headers']['status-code']);
$team2Id = $response['body']['$id'];
/**
* Cleanup, so I don't invalidate some listTeams requests by mistake
*/
$response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team1Id, \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
], $this->getHeaders()));
$this->assertEquals(204, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team2Id, \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
], $this->getHeaders()));
$this->assertEquals(204, $response['headers']['status-code']);
}
}

View file

@ -22,13 +22,13 @@ class ResponseTest extends TestCase
public function testSetFilter()
{
$this->assertEquals($this->object->isFilter(), false);
$this->assertEquals($this->object->hasFilter(), false);
$this->assertEquals($this->object->getFilter(), null);
$filter = new V06();
$this->object->setFilter($filter);
$this->assertEquals($this->object->isFilter(), true);
$this->assertEquals($this->object->hasFilter(), true);
$this->assertEquals($this->object->getFilter(), $filter);
}
}