From a585a9090ad995dab4097164be9a1a4194e29d44 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 7 Oct 2021 17:35:17 +0200 Subject: [PATCH] fix realtime with db refactor --- app/config/collections2.php | 51 ++- app/controllers/api/functions.php | 4 +- app/controllers/shared/api.php | 20 +- app/http.php | 1 - app/init.php | 2 - app/realtime.php | 294 +++++++++--------- src/Appwrite/Messaging/Adapter/Realtime.php | 13 +- .../Utopia/Response/Model/Execution.php | 12 +- tests/e2e/Services/Realtime/RealtimeBase.php | 93 +++--- .../unit/Messaging/MessagingChannelsTest.php | 6 +- tests/unit/Messaging/MessagingGuestTest.php | 4 +- tests/unit/Messaging/MessagingTest.php | 4 +- 12 files changed, 271 insertions(+), 233 deletions(-) diff --git a/app/config/collections2.php b/app/config/collections2.php index 052ba7cd00..cd867b7002 100644 --- a/app/config/collections2.php +++ b/app/config/collections2.php @@ -2282,7 +2282,56 @@ 'orders' => [Database::ORDER_DESC], ], ], - ] + ], + 'realtime' => [ + '$collection' => Database::METADATA, + '$id' => 'realtime', + 'name' => 'Realtime Connections', + 'attributes' => [ + [ + '$id' => 'container', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => 'timestamp', + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => 'value', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16384, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], //TODO: use json filter + ] + ], + 'indexes' => [ + [ + '$id' => '_key_timestamp', + 'type' => Database::INDEX_KEY, + 'attributes' => ['timestamp'], + 'lengths' => [], + 'orders' => [Database::ORDER_DESC], + ], + ] + ], ]; return $collections; \ No newline at end of file diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 00ed181239..63a44b2498 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -699,10 +699,10 @@ ])); Authorization::reset(); - + $jwt = ''; // initialize if (!$user->isEmpty()) { // If userId exists, generate a JWT for function - + $sessions = $user->getAttribute('sessions', []); $current = new Document(); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 37a618bc59..210cb46912 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -1,13 +1,13 @@ getParam('event'), $payload); Realtime::send( - $project->getId(), - $response->getPayload(), - $events->getParam('event'), - $target['channels'], - $target['roles'], + $project->getId(), + $response->getPayload(), + $events->getParam('event'), + $target['channels'], + $target['roles'], [ 'permissionsChanged' => $target['permissionsChanged'], 'userId' => $events->getParam('userId') @@ -221,11 +221,11 @@ ); } } - + if (!empty($audits->getParam('event'))) { $audits->trigger(); } - + if (!empty($deletes->getParam('type')) && !empty($deletes->getParam('document'))) { $deletes->trigger(); } @@ -233,13 +233,13 @@ if (!empty($database->getParam('type')) && !empty($database->getParam('document'))) { $database->trigger(); } - + $route = $utopia->match($request); if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled' && $project->getId() && $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin && !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode - + $usage ->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage')) ->setParam('networkResponseSize', $response->getSize()) diff --git a/app/http.php b/app/http.php index b4830d9def..82b6e73e3e 100644 --- a/app/http.php +++ b/app/http.php @@ -131,7 +131,6 @@ } $dbForConsole->createCollection($key, $attributes, $indexes); - } Console::success('[Setup] - Server database init completed...'); diff --git a/app/init.php b/app/init.php index f399656218..118cf777be 100644 --- a/app/init.php +++ b/app/init.php @@ -28,11 +28,9 @@ use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; use Appwrite\Network\Validator\URL; -use Appwrite\Event\Realtime; use Appwrite\OpenSSL\OpenSSL; use Appwrite\Stats\Stats; use Utopia\App; -use Utopia\CLI\Console; use Utopia\View; use Utopia\Config\Config; use Utopia\Locale\Locale; diff --git a/app/realtime.php b/app/realtime.php index 5eca5c1b4e..501a72bdf2 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -18,6 +18,10 @@ use Utopia\Cache\Adapter\Redis as RedisCache; use Utopia\Cache\Cache; use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Document; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Registry\Registry; use Utopia\Swoole\Request; use Utopia\WebSocket\Server; use Utopia\WebSocket\Adapter; @@ -40,124 +44,121 @@ $stats->create(); $containerId = uniqid(); -$documentId = null; +$statsDocument = null; $adapter = new Adapter\Swoole(port: App::getEnv('PORT', 80)); $adapter->setPackageMaxLength(64000); // Default maximum Package Size (64kb) $server = new Server($adapter); -$server->onStart(function () use ($stats, $register, $containerId, &$documentId) { - Console::success('Server started succefully'); +function getDatabase(Registry &$register, string $namespace) +{ + $db = $register->get('dbPool')->get(); + $redis = $register->get('redisPool')->get(); - // $getConsoleDb = function () use ($register) { - // $db = $register->get('dbPool')->get(); - // $cache = $register->get('redisPool')->get(); + $cache = new Cache(new RedisCache($redis)); + $database = new Database(new MariaDB($db), $cache); + $database->setNamespace($namespace); - // $cache = new Cache(new RedisCache($cache)); - // $database = new Database(new MariaDB($db), $cache); + return [ + $database, + function () use ($register, $db, $redis) { + $register->get('dbPool')->put($db); + $register->get('redisPool')->put($redis); + } + ]; +}; - // return [ - // $database, - // function () use ($register, $db, $cache) { - // $register->get('dbPool')->put($db); - // $register->get('redisPool')->put($cache); - // } - // ]; - // }; +$server->onStart(function () use ($stats, $register, $containerId, &$statsDocument) { + Console::success('Server started succefully'); /** * Create document for this worker to share stats across Containers. */ - // go(function () use ($getConsoleDb, $containerId, &$documentId) { - // try { - // [$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb); - // // $document = [ - // // '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, - // // '$permissions' => [ - // // 'read' => ['*'], - // // 'write' => ['*'], - // // ], - // // 'container' => $containerId, - // // 'timestamp' => time(), - // // 'value' => '{}' - // // ]; - // // Authorization::disable(); - // // $document = $consoleDb->createDocument($document); - // // Authorization::enable(); - // // $documentId = $document->getId(); - // } catch (\Throwable $th) { - // Console::error('[Error] Type: ' . get_class($th)); - // Console::error('[Error] Message: ' . $th->getMessage()); - // Console::error('[Error] File: ' . $th->getFile()); - // Console::error('[Error] Line: ' . $th->getLine()); - // } finally { - // call_user_func($returnConsoleDb); - // } - // }); - - // /** - // * Save current connections to the Database every 5 seconds. - // */ - // Timer::tick(5000, function () use ($stats, $getConsoleDb, $containerId, &$documentId) { - // foreach ($stats as $projectId => $value) { - // if (empty($value['connections']) && empty($value['messages'])) { - // continue; - // } - - // $connections = $stats->get($projectId, 'connections'); - // $messages = $stats->get($projectId, 'messages'); - - // $usage = new Event('v1-usage', 'UsageV1'); - // $usage - // ->setParam('projectId', $projectId) - // ->setParam('realtimeConnections', $connections) - // ->setParam('realtimeMessages', $messages) - // ->setParam('networkRequestSize', 0) - // ->setParam('networkResponseSize', 0); - - // $stats->set($projectId, [ - // 'messages' => 0, - // 'connections' => 0 - // ]); - - // if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { - // $usage->trigger(); - // } - // } - // $payload = []; - // foreach ($stats as $projectId => $value) { - // if (!empty($value['connectionsTotal'])) { - // $payload[$projectId] = $stats->get($projectId, 'connectionsTotal'); - // } - // } - // if (empty($payload)) { - // return; - // } - - // try { - // [$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb); - - // // $consoleDb->updateDocument([ - // // '$id' => $documentId, - // // '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, - // // '$permissions' => [ - // // 'read' => ['*'], - // // 'write' => ['*'], - // // ], - // // 'container' => $containerId, - // // 'timestamp' => time(), - // // 'value' => json_encode($payload) - // // ]); - // } catch (\Throwable $th) { - // Console::error('[Error] Type: ' . get_class($th)); - // Console::error('[Error] Message: ' . $th->getMessage()); - // Console::error('[Error] File: ' . $th->getFile()); - // Console::error('[Error] Line: ' . $th->getLine()); - // } finally { - // call_user_func($returnConsoleDb); - // } - // }); + go(function () use ($register, $containerId, &$statsDocument) { + try { + [$database, $returnDatabase] = getDatabase($register, 'project_console_internal'); + $document = new Document([ + '$id' => $database->getId(), + '$collection' => 'realtime', + '$read' => [], + '$write' => [], + 'container' => $containerId, + 'timestamp' => time(), + 'value' => '{}' + ]); + $statsDocument = Authorization::skip(function () use ($database, $document) { + return $database->createDocument('realtime', $document); + }); + } catch (\Throwable $th) { + Console::error('[Error] Type: ' . get_class($th)); + Console::error('[Error] Message: ' . $th->getMessage()); + Console::error('[Error] File: ' . $th->getFile()); + Console::error('[Error] Line: ' . $th->getLine()); + } finally { + call_user_func($returnDatabase); + } + }); + + /** + * Save current connections to the Database every 5 seconds. + */ + Timer::tick(5000, function () use ($register, $stats, $containerId, &$statsDocument) { + /** @var Document $statsDocument */ + foreach ($stats as $projectId => $value) { + if (empty($value['connections']) && empty($value['messages'])) { + continue; + } + + $connections = $stats->get($projectId, 'connections'); + $messages = $stats->get($projectId, 'messages'); + + $usage = new Event('v1-usage', 'UsageV1'); + $usage + ->setParam('projectId', $projectId) + ->setParam('realtimeConnections', $connections) + ->setParam('realtimeMessages', $messages) + ->setParam('networkRequestSize', 0) + ->setParam('networkResponseSize', 0); + + $stats->set($projectId, [ + 'messages' => 0, + 'connections' => 0 + ]); + + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $usage->trigger(); + } + } + $payload = []; + foreach ($stats as $projectId => $value) { + if (!empty($value['connectionsTotal'])) { + $payload[$projectId] = $stats->get($projectId, 'connectionsTotal'); + } + } + if (empty($payload) || empty($statsDocument)) { + return; + } + + try { + [$database, $returnDatabase] = getDatabase($register, 'project_console_internal'); + + $statsDocument + ->setAttribute('timestamp', time()) + ->setAttribute('value', json_encode($payload)); + + Authorization::skip(function () use ($database, $statsDocument) { + $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument); + }); + } catch (\Throwable $th) { + Console::error('[Error] Type: ' . get_class($th)); + Console::error('[Error] Message: ' . $th->getMessage()); + Console::error('[Error] File: ' . $th->getFile()); + Console::error('[Error] Line: ' . $th->getLine()); + } finally { + call_user_func($returnDatabase); + } + }); }); $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime) { @@ -171,21 +172,16 @@ * Sending current connections to project channels on the console project every 5 seconds. */ if ($realtime->hasSubscriber('console', 'role:member', 'project')) { - $db = $register->get('dbPool')->get(); - $redis = $register->get('redisPool')->get(); - $cache = new Cache(new RedisCache($redis)); - $database = new Database(new MariaDB($db), $cache); - $database->setNamespace('project_console_internal'); + [$database, $returnDatabase] = getDatabase($register, 'project_console_internal'); $payload = []; - $list = []; - // $list = $consoleDb->getCollection([ - // 'filters' => [ - // '$collection=' . Database::SYSTEM_COLLECTION_CONNECTIONS, - // 'timestamp>' . (time() - 15) - // ], - // ]); + + $list = Authorization::skip(function () use ($database) { + return $database->find('realtime', [ + new Query('timestamp', Query::TYPE_GREATER, [(time() - 15)]) + ]); + }); /** * Aggregate stats across containers. @@ -224,8 +220,7 @@ ])); } - $register->get('dbPool')->put($db); - $register->get('redisPool')->put($redis); + call_user_func($returnDatabase); } /** * Sending test message for SDK E2E tests every 5 seconds. @@ -284,12 +279,7 @@ return; } - $db = $register->get('dbPool')->get(); - $cache = $register->get('redisPool')->get(); - - $cache = new Cache(new RedisCache($cache)); - $database = new Database(new MariaDB($db), $cache); - $database->setNamespace('project_' . $projectId .'_internal'); + [$database, $returnDatabase] = getDatabase($register, 'project_' . $projectId . '_internal'); $user = $database->getDocument('users', $userId); @@ -297,8 +287,7 @@ $realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']); - $register->get('dbPool')->put($db); - $register->get('redisPool')->put($cache); + call_user_func($returnDatabase); } $receivers = $realtime->getSubscribers($event); @@ -374,7 +363,7 @@ $cache = new Cache(new RedisCache($redis)); $database = new Database(new MariaDB($db), $cache); - $database->setNamespace('project_' . $project->getId() .'_internal'); + $database->setNamespace('project_' . $project->getId() . '_internal'); /* * Project Check @@ -388,17 +377,16 @@ * * Abuse limits are connecting 128 times per minute and ip address. */ - // $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $database); - // $timeLimit - // ->setParam('{ip}', $request->getIP()) - // ->setParam('{url}', $request->getURI()) - // ->setup(); + $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $database); + $timeLimit + ->setParam('{ip}', $request->getIP()) + ->setParam('{url}', $request->getURI()); - // $abuse = new Abuse($timeLimit); + $abuse = new Abuse($timeLimit); - // if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { - // throw new Exception('Too many requests', 1013); - // } + if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { + throw new Exception('Too many requests', 1013); + } /* * Validate Client Domain - Check to avoid CSRF attack. @@ -457,7 +445,6 @@ Console::error('[Error] Connection Error'); Console::error('[Error] Code: ' . $response['data']['code']); Console::error('[Error] Message: ' . $response['data']['message']); - var_dump($th->getFile(), $th->getLine(), $th->getTraceAsString()); } if ($th instanceof PDOException) { @@ -476,28 +463,27 @@ try { $response = new Response(new SwooleResponse()); $db = $register->get('dbPool')->get(); - $cache = $register->get('redisPool')->get(); + $redis = $register->get('redisPool')->get(); - $cache = new Cache(new RedisCache($cache)); + $cache = new Cache(new RedisCache($redis)); $database = new Database(new MariaDB($db), $cache); - $database->setNamespace('project_' . $realtime->connections[$connection]['projectId'] .'_internal'); + $database->setNamespace('project_' . $realtime->connections[$connection]['projectId'] . '_internal'); /* * Abuse Check * * Abuse limits are sending 32 times per minute and connection. */ - // $timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $database); - // $timeLimit - // ->setParam('{connection}', $connection) - // ->setParam('{container}', $containerId) - // ->setup(); + $timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $database); + $timeLimit + ->setParam('{connection}', $connection) + ->setParam('{container}', $containerId); - // $abuse = new Abuse($timeLimit); + $abuse = new Abuse($timeLimit); - // if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { - // throw new Exception('Too many messages', 1013); - // } + if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { + throw new Exception('Too many messages', 1013); + } $message = json_decode($message, true); @@ -506,7 +492,7 @@ } switch ($message['type']) { - /** + /** * This type is used to authenticate. */ case 'authentication': @@ -515,8 +501,8 @@ } $session = Auth::decodeSession($message['data']['session']); - Auth::$unique = $session['id']; - Auth::$secret = $session['secret']; + Auth::$unique = $session['id'] ?? ''; + Auth::$secret = $session['secret'] ?? ''; $user = $database->getDocument('users', Auth::$unique); @@ -564,7 +550,7 @@ } } finally { $register->get('dbPool')->put($db); - $register->get('redisPool')->put($cache); + $register->get('redisPool')->put($redis); } }); diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index 57cbb53ae5..0aab93f52b 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -184,7 +184,7 @@ public function getSubscribers(array $event) */ if ( \array_key_exists($channel, $this->subscriptions[$event['project']][$role]) - && (\in_array($role, $event['roles']) || \in_array('*', $event['roles'])) + && (\in_array($role, $event['roles']) || \in_array('role:all', $event['roles'])) ) { /** * Saving all connections that are allowed to receive this event. @@ -277,28 +277,29 @@ public static function fromPayload(string $event, Document $payload): array case strpos($event, 'database.collections.') === 0: $channels[] = 'collections'; $channels[] = 'collections.' . $payload->getId(); - $roles = $payload->getAttribute('$permissions.read'); + $roles = $payload->getRead(); break; case strpos($event, 'database.documents.') === 0: $channels[] = 'documents'; $channels[] = 'collections.' . $payload->getAttribute('$collection') . '.documents'; $channels[] = 'documents.' . $payload->getId(); - $roles = $payload->getAttribute('$permissions.read'); + $roles = $payload->getRead(); break; case strpos($event, 'storage.') === 0: $channels[] = 'files'; $channels[] = 'files.' . $payload->getId(); - $roles = $payload->getAttribute('$permissions.read'); + $roles = $payload->getRead(); break; case strpos($event, 'functions.executions.') === 0: - if (!empty($payload->getAttribute('$permissions.read'))) { + \var_dump($payload->getArrayCopy()); + if (!empty($payload->getRead())) { $channels[] = 'executions'; $channels[] = 'executions.' . $payload->getId(); $channels[] = 'functions.' . $payload->getAttribute('functionId'); - $roles = $payload->getAttribute('$permissions.read'); + $roles = $payload->getRead(); } break; } diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index 9d85d0cfec..37c1f7b67b 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -16,12 +16,12 @@ public function __construct() 'default' => '', 'example' => '5e5ea5c16897e', ]) - ->addRule('$permissions', [ - 'type' => Response::MODEL_PERMISSIONS, - 'description' => 'Execution permissions.', - 'default' => new \stdClass, - 'example' => new \stdClass, - 'array' => false, + ->addRule('$read', [ + 'type' => self::TYPE_STRING, + 'description' => 'Execution read permissions.', + 'default' => '', + 'example' => 'role:all', + 'array' => true, ]) ->addRule('functionId', [ 'type' => self::TYPE_STRING, diff --git a/tests/e2e/Services/Realtime/RealtimeBase.php b/tests/e2e/Services/Realtime/RealtimeBase.php index d1afacb7a7..da5f3ce114 100644 --- a/tests/e2e/Services/Realtime/RealtimeBase.php +++ b/tests/e2e/Services/Realtime/RealtimeBase.php @@ -190,7 +190,6 @@ public function testManualAuthentication() $user = $this->getUser(); $userId = $user['$id'] ?? ''; $session = $user['session'] ?? ''; - $projectId = $this->getProject()['$id']; /** * Test for SUCCESS @@ -617,27 +616,11 @@ public function testChannelDatabase() 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ + 'collectionId' => 'unique()', 'name' => 'Actors', - 'read' => ['*'], - 'write' => ['*'], - 'rules' => [ - [ - 'label' => 'First Name', - 'key' => 'firstName', - 'type' => 'text', - 'default' => '', - 'required' => true, - 'array' => false - ], - [ - 'label' => 'Last Name', - 'key' => 'lastName', - 'type' => 'text', - 'default' => '', - 'required' => true, - 'array' => false - ], - ], + 'read' => ['role:all'], + 'write' => ['role:all'], + 'permission' => 'collection' ]); $response = json_decode($client->receive(), true); @@ -655,6 +638,24 @@ public function testChannelDatabase() $data = ['actorsId' => $actors['body']['$id']]; + $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'name', + 'size' => 256, + 'required' => true, + ]); + + $this->assertEquals($name['headers']['status-code'], 201); + $this->assertEquals($name['body']['key'], 'name'); + $this->assertEquals($name['body']['type'], 'string'); + $this->assertEquals($name['body']['size'], 256); + $this->assertEquals($name['body']['required'], true); + + sleep(2); + /** * Test Document Create */ @@ -662,12 +663,12 @@ public function testChannelDatabase() 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ + 'documentId' => 'unique()', 'data' => [ - 'firstName' => 'Chris', - 'lastName' => 'Evans', + 'name' => 'Chris Evans' ], - 'read' => ['*'], - 'write' => ['*'], + 'read' => ['role:all'], + 'write' => ['role:all'], ]); $response = json_decode($client->receive(), true); @@ -683,6 +684,7 @@ public function testChannelDatabase() $this->assertContains('collections.' . $actors['body']['$id'] . '.documents', $response['data']['channels']); $this->assertEquals('database.documents.create', $response['data']['event']); $this->assertNotEmpty($response['data']['payload']); + $this->assertEquals($response['data']['payload']['name'], 'Chris Evans'); $data['documentId'] = $document['body']['$id']; @@ -693,12 +695,12 @@ public function testChannelDatabase() 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ + 'documentId' => 'unique()', 'data' => [ - 'firstName' => 'Chris1', - 'lastName' => 'Evans2', + 'name' => 'Chris Evans 2' ], - 'read' => ['*'], - 'write' => ['*'], + 'read' => ['role:all'], + 'write' => ['role:all'], ]); $response = json_decode($client->receive(), true); @@ -715,8 +717,8 @@ public function testChannelDatabase() $this->assertEquals('database.documents.update', $response['data']['event']); $this->assertNotEmpty($response['data']['payload']); - $this->assertEquals($response['data']['payload']['firstName'], 'Chris1'); - $this->assertEquals($response['data']['payload']['lastName'], 'Evans2'); + $this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2'); + /** * Test Document Delete @@ -725,13 +727,12 @@ public function testChannelDatabase() 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ + 'documentId' => 'unique()', 'data' => [ - 'firstName' => 'Bradly', - 'lastName' => 'Cooper', - + 'name' => 'Bradley Cooper' ], - 'read' => ['*'], - 'write' => ['*'], + 'read' => ['role:all'], + 'write' => ['role:all'], ]); $client->receive(); @@ -754,6 +755,7 @@ public function testChannelDatabase() $this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']); $this->assertEquals('database.documents.delete', $response['data']['event']); $this->assertNotEmpty($response['data']['payload']); + $this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper'); $client->close(); } @@ -786,9 +788,10 @@ public function testChannelFiles() 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ + 'fileId' => 'unique()', 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), - 'read' => ['*'], - 'write' => ['*'], + 'read' => ['role:all'], + 'write' => ['role:all'], 'folderId' => 'xyz', ]); @@ -814,8 +817,8 @@ public function testChannelFiles() 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'read' => ['*'], - 'write' => ['*'], + 'read' => ['role:all'], + 'write' => ['role:all'], ]); $response = json_decode($client->receive(), true); @@ -878,16 +881,17 @@ public function testChannelExecutions() $this->assertEquals($user['$id'], $response['data']['user']['$id']); /** - * Test File Create + * Test Functions Create */ - $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ + $function = $this->client->call(Client::METHOD_POST, '/functions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ + ], [ + 'functionId' => 'unique()', 'name' => 'Test', + 'execute' => ['role:member'], 'runtime' => 'php-8.0', - 'execute' => ['*'], 'timeout' => 10, ]); @@ -988,6 +992,7 @@ public function testChannelTeams(): array 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ + 'teamId' => 'unique()', 'name' => 'Arsenal' ]); diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index d412573334..b4001bd0fc 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -3,7 +3,7 @@ namespace Appwrite\Tests; use Appwrite\Auth\Auth; -use Appwrite\Database\Document; +use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; @@ -146,14 +146,14 @@ public function testSubscriptions() } /** - * Tests Wildcard (*) Permissions on every channel. + * Tests Wildcard (role:all) Permissions on every channel. */ public function testWildcardPermission() { foreach ($this->allChannels as $index => $channel) { $event = [ 'project' => '1', - 'roles' => ['*'], + 'roles' => ['role:all'], 'data' => [ 'channels' => [ 0 => $channel, diff --git a/tests/unit/Messaging/MessagingGuestTest.php b/tests/unit/Messaging/MessagingGuestTest.php index 57714b1366..f6b5e22cda 100644 --- a/tests/unit/Messaging/MessagingGuestTest.php +++ b/tests/unit/Messaging/MessagingGuestTest.php @@ -20,7 +20,7 @@ public function testGuest() $event = [ 'project' => '1', - 'roles' => ['*'], + 'roles' => ['role:all'], 'data' => [ 'channels' => [ 0 => 'documents', @@ -95,7 +95,7 @@ public function testGuest() $this->assertEmpty($receivers); - $event['roles'] = ['*']; + $event['roles'] = ['role:all']; $event['data']['channels'] = ['documents.123']; $receivers = $realtime->getSubscribers($event); diff --git a/tests/unit/Messaging/MessagingTest.php b/tests/unit/Messaging/MessagingTest.php index 19285d0307..dd258d3ae6 100644 --- a/tests/unit/Messaging/MessagingTest.php +++ b/tests/unit/Messaging/MessagingTest.php @@ -29,7 +29,7 @@ public function testUser() $event = [ 'project' => '1', - 'roles' => ['*'], + 'roles' => ['role:all'], 'data' => [ 'channels' => [ 0 => 'account.123', @@ -103,7 +103,7 @@ public function testUser() $this->assertEmpty($receivers); - $event['roles'] = ['*']; + $event['roles'] = ['role:all']; $event['data']['channels'] = ['documents.123']; $receivers = $realtime->getSubscribers($event);