diff --git a/.env b/.env index 43e14f843f..09abb07be2 100644 --- a/.env +++ b/.env @@ -79,7 +79,7 @@ _APP_MAINTENANCE_RETENTION_CACHE=2592000 _APP_MAINTENANCE_RETENTION_EXECUTION=1209600 _APP_MAINTENANCE_RETENTION_ABUSE=86400 _APP_MAINTENANCE_RETENTION_AUDIT=1209600 -_APP_USAGE_AGGREGATION_INTERVAL=20 +_APP_USAGE_AGGREGATION_INTERVAL=30 _APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000 _APP_MAINTENANCE_RETENTION_SCHEDULES=86400 _APP_USAGE_STATS=enabled diff --git a/README.md b/README.md index 62b084d320..88b4173f1d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -> Great news! Appwrite Cloud is now in public beta! Sign up at [cloud.appwrite.io](https://cloud.appwrite.io) for a hassle-free, hosted experience. Join us in the Cloud today! ☁️🎉 +> Our Appwrite Init event has concluded. You can check out all the new and upcoming features [on our Init website](https://appwrite.io/init) 🚀

diff --git a/app/cli.php b/app/cli.php index 559378bc57..1a8c785a30 100644 --- a/app/cli.php +++ b/app/cli.php @@ -3,29 +3,29 @@ require_once __DIR__ . '/init.php'; require_once __DIR__ . '/controllers/general.php'; -use Appwrite\Event\Delete; use Appwrite\Event\Certificate; +use Appwrite\Event\Delete; use Appwrite\Event\Func; use Appwrite\Event\Hamster; use Appwrite\Platform\Appwrite; -use Utopia\CLI\CLI; -use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Service; use Utopia\App; -use Utopia\CLI\Console; use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; +use Utopia\CLI\CLI; +use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Logger\Log; +use Utopia\Platform\Service; use Utopia\Pools\Group; use Utopia\Queue\Connection; use Utopia\Registry\Registry; Authorization::disable(); -CLI::setResource('register', fn()=>$register); +CLI::setResource('register', fn () => $register); CLI::setResource('cache', function ($pools) { $list = Config::getParam('pools-cache', []); diff --git a/app/config/avatars/credit-cards.php b/app/config/avatars/credit-cards.php index aaef17ee3f..1aa22c4174 100644 --- a/app/config/avatars/credit-cards.php +++ b/app/config/avatars/credit-cards.php @@ -17,4 +17,4 @@ return [ 'visa' => ['name' => 'Visa', 'path' => __DIR__ . '/credit-cards/visa.png'], 'mir' => ['name' => 'MIR', 'path' => __DIR__ . '/credit-cards/mir.png'], 'maestro' => ['name' => 'Maestro', 'path' => __DIR__ . '/credit-cards/maestro.png'] - ]; +]; diff --git a/app/config/collections.php b/app/config/collections.php index 4d3544f964..3c61dd4e9b 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -34,6 +34,28 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => 'resourceType', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 255, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('mimeType'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 255, // https://tools.ietf.org/html/rfc4288#section-4.2 + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'accessedAt', 'type' => Database::VAR_DATETIME, diff --git a/app/config/runtimes-v2.php b/app/config/runtimes-v2.php index c24aaa109e..d249946d05 100644 --- a/app/config/runtimes-v2.php +++ b/app/config/runtimes-v2.php @@ -4,8 +4,8 @@ * List of Appwrite Cloud Functions supported runtimes */ -use Utopia\App; use Appwrite\Runtimes\Runtimes; +use Utopia\App; $runtimes = new Runtimes('v2'); diff --git a/app/config/usage.php b/app/config/usage.php index 2179bcce54..a0d3f9f725 100644 --- a/app/config/usage.php +++ b/app/config/usage.php @@ -1,24 +1,24 @@ [ - 'period' => '1h', - 'limit' => 24, - 'factor' => 3600, - ], - '7d' => [ - 'period' => '1d', - 'limit' => 7, - 'factor' => 86400, - ], - '30d' => [ - 'period' => '1d', - 'limit' => 30, - 'factor' => 86400, - ], - '90d' => [ - 'period' => '1d', - 'limit' => 90, - 'factor' => 86400, - ], + '24h' => [ + 'period' => '1h', + 'limit' => 24, + 'factor' => 3600, + ], + '7d' => [ + 'period' => '1d', + 'limit' => 7, + 'factor' => 86400, + ], + '30d' => [ + 'period' => '1d', + 'limit' => 30, + 'factor' => 86400, + ], + '90d' => [ + 'period' => '1d', + 'limit' => 90, + 'factor' => 86400, + ], ]; diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index ae647beeba..ddb85e0d19 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -6,26 +6,25 @@ use Appwrite\Auth\MFA\Challenge; use Appwrite\Auth\MFA\Type; use Appwrite\Auth\MFA\Type\TOTP; use Appwrite\Auth\OAuth2\Exception as OAuth2Exception; +use Appwrite\Auth\Phrase; use Appwrite\Auth\Validator\Password; +use Appwrite\Auth\Validator\PasswordDictionary; +use Appwrite\Auth\Validator\PasswordHistory; +use Appwrite\Auth\Validator\PersonalData; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; +use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Auth\Phrase; +use Appwrite\Event\Messaging; use Appwrite\Extend\Exception; +use Appwrite\Hooks\Hooks; use Appwrite\Network\Validator\Email; -use Utopia\Database\Exception\Query as QueryException; -use Utopia\Validator\Host; -use Utopia\Validator\URL; -use Utopia\Validator\Boolean; use Appwrite\OpenSSL\OpenSSL; use Appwrite\Template\Template; use Appwrite\URL\URL as URLParser; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Identities; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use MaxMind\Db\Reader; @@ -33,26 +32,27 @@ use Utopia\App; use Utopia\Audit\Audit as EventAudit; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Query; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; +use Utopia\Validator\Boolean; +use Utopia\Validator\Host; use Utopia\Validator\Text; +use Utopia\Validator\URL; use Utopia\Validator\WhiteList; -use Appwrite\Auth\Validator\PasswordHistory; -use Appwrite\Auth\Validator\PasswordDictionary; -use Appwrite\Auth\Validator\PersonalData; -use Appwrite\Event\Delete; -use Appwrite\Event\Messaging; -use Appwrite\Hooks\Hooks; $oauthDefaultSuccess = '/auth/oauth2/success'; $oauthDefaultFailure = '/auth/oauth2/failure'; @@ -267,9 +267,9 @@ App::post('/v1/account') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$internalId'); - $user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -456,7 +456,7 @@ App::delete('/v1/account/sessions') if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { $session->setAttribute('current', true); - // If current session delete the cookies too + // If current session delete the cookies too $response ->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) ->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); @@ -883,7 +883,7 @@ App::post('/v1/account/sessions/anonymous') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$internalId'); - Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); // Create session token $duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; @@ -912,10 +912,10 @@ App::post('/v1/account/sessions/anonymous') Authorization::setRole(Role::user($user->getId())->toString()); $session = $dbForProject->createDocument('sessions', $session-> setAttribute('$permissions', [ - Permission::read(Role::user($user->getId())), - Permission::update(Role::user($user->getId())), - Permission::delete(Role::user($user->getId())), - ])); + Permission::read(Role::user($user->getId())), + Permission::update(Role::user($user->getId())), + Permission::delete(Role::user($user->getId())), + ])); $dbForProject->purgeCachedDocument('users', $user->getId()); @@ -991,9 +991,9 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.') - ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) - ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.') + ->param('success', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('failure', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->inject('request') ->inject('response') @@ -1359,7 +1359,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'accessedAt' => DateTime::now(), ]); $user->removeAttribute('$internalId'); - $userDoc = Authorization::skip(fn() => $dbForProject->createDocument('users', $user)); + $userDoc = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), @@ -1477,7 +1477,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $query['secret'] = $secret; $query['userId'] = $user->getId(); - // If the `token` param is not set, we persist the session in a cookie + // If the `token` param is not set, we persist the session in a cookie } else { $detector = new Detector($request->getUserAgent('UNKNOWN')); $record = $geodb->get($request->getIP()); @@ -1573,9 +1573,9 @@ App::get('/v1/account/tokens/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.') - ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) - ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.') + ->param('success', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('failure', '', fn ($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->inject('request') ->inject('response') @@ -1648,7 +1648,7 @@ App::post('/v1/account/tokens/magic-url') ->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}']) ->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('email', '', new Email(), 'User email.') - ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) + ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true) ->inject('request') ->inject('response') @@ -2240,7 +2240,7 @@ App::post('/v1/account/tokens/phone') $user->removeAttribute('$internalId'); Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { - $target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([ + $target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([ '$permissions' => [ Permission::read(Role::user($user->getId())), Permission::update(Role::user($user->getId())), @@ -2369,13 +2369,13 @@ App::post('/v1/account/jwt') $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic(new Document(['jwt' => $jwt->encode([ - // 'uid' => 1, - // 'aud' => 'http://site.com', - // 'scopes' => ['user'], - // 'iss' => 'http://api.mysite.com', - 'userId' => $user->getId(), - 'sessionId' => $current->getId(), - ])]), Response::MODEL_JWT); + // 'uid' => 1, + // 'aud' => 'http://site.com', + // 'scopes' => ['user'], + // 'iss' => 'http://api.mysite.com', + 'userId' => $user->getId(), + 'sessionId' => $current->getId(), + ])]), Response::MODEL_JWT); }); App::get('/v1/account/prefs') @@ -2460,7 +2460,7 @@ App::get('/v1/account/logs') } $response->dynamic(new Document([ - 'total' => $audit->countLogsByUser($user->getId()), + 'total' => $audit->countLogsByUser($user->getInternalId()), 'logs' => $output, ]), Response::MODEL_LOG_LIST); }); @@ -3095,7 +3095,7 @@ App::post('/v1/account/verification') ->label('sdk.response.model', Response::MODEL_TOKEN) ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{userId}') - ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page + ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page ->inject('request') ->inject('response') ->inject('project') @@ -3264,7 +3264,7 @@ App::put('/v1/account/verification') ->inject('queueForEvents') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); + $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -3436,7 +3436,7 @@ App::put('/v1/account/verification/phone') ->inject('queueForEvents') ->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { - $profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); + $profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); @@ -4262,7 +4262,7 @@ App::delete('/v1/account/targets/:targetId/push') ->inject('response') ->inject('dbForProject') ->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject) { - $target = Authorization::skip(fn() => $dbForProject->getDocument('targets', $targetId)); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index ffcfb8f10a..6304482b14 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -3,6 +3,8 @@ use Appwrite\Extend\Exception; use Appwrite\URL\URL as URLParse; use Appwrite\Utopia\Response; +use chillerlan\QRCode\QRCode; +use chillerlan\QRCode\QROptions; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; @@ -21,8 +23,6 @@ use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\URL; use Utopia\Validator\WhiteList; -use chillerlan\QRCode\QRCode; -use chillerlan\QRCode\QROptions; $avatarCallback = function (string $type, string $code, int $width, int $height, int $quality, Response $response) { @@ -76,7 +76,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro } if (empty($gitHubSession)) { - throw new Exception(Exception::GENERAL_UNKNOWN, 'GitHub session not found.'); + throw new Exception(Exception::USER_SESSION_NOT_FOUND, 'GitHub session not found.'); } $provider = $gitHubSession->getAttribute('provider', ''); diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 6a9cb73a67..2b655ab5d8 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -45,8 +45,8 @@ use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\FloatValidator; -use Utopia\Validator\IP; use Utopia\Validator\Integer; +use Utopia\Validator\IP; use Utopia\Validator\JSON; use Utopia\Validator\Nullable; use Utopia\Validator\Range; @@ -752,7 +752,7 @@ App::post('/v1/databases/:databaseId/collections') ->inject('queueForEvents') ->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $queueForEvents) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -813,7 +813,7 @@ App::get('/v1/databases/:databaseId/collections') ->inject('mode') ->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -875,7 +875,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId') ->inject('mode') ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -911,7 +911,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs') ->inject('geodb') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -1017,7 +1017,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->inject('queueForEvents') ->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $queueForEvents) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -1081,7 +1081,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->inject('mode') ->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -1616,7 +1616,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati $key ??= $relatedCollectionId; $twoWayKey ??= $collectionId; - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -1719,7 +1719,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject) { /** @var Document $database */ - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -1753,7 +1753,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') if ($cursor) { $attributeId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn() => $dbForProject->find('attributes', [ + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('attributes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), Query::equal('databaseInternalId', [$database->getInternalId()]), Query::equal('key', [$attributeId]), @@ -1807,7 +1807,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -2300,7 +2300,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->inject('queueForEvents') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { - $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -2413,7 +2413,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->inject('queueForEvents') ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { - $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -2437,7 +2437,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') } // Convert Document[] to array of attribute metadata - $oldAttributes = \array_map(fn($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); + $oldAttributes = \array_map(fn ($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); $oldAttributes[] = [ 'key' => '$id', @@ -2575,7 +2575,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject) { /** @var Document $database */ - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -2598,14 +2598,14 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') /** * Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries */ - $cursor = \array_filter($queries, function ($query) { + $cursor = \array_filter($queries, function ($query) { return \in_array($query->getMethod(), [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE]); - }); - $cursor = reset($cursor); + }); + $cursor = reset($cursor); if ($cursor) { $indexId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn() => $dbForProject->find('indexes', [ + $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), Query::equal('databaseInternalId', [$database->getInternalId()]), Query::equal('key', [$indexId]), @@ -2645,7 +2645,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('dbForProject') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -2688,7 +2688,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->inject('queueForEvents') ->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { - $db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($db->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -2771,7 +2771,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, '$id is not allowed for creating new documents, try update instead'); } - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -2780,7 +2780,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -2848,7 +2848,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -2868,7 +2868,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($relations as &$relation) { @@ -2882,7 +2882,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') } if ($relation instanceof Document) { $current = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId()) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId()) ); if ($current->isEmpty()) { @@ -2912,13 +2912,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $checkPermissions($collection, $document, Database::PERMISSION_CREATE); - try { - $document = $dbForProject->createDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } catch (DuplicateException $exception) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); - } + try { + $document = $dbForProject->createDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document); + } catch (StructureException $exception) { + throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); + } catch (DuplicateException $exception) { + throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); + } // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { @@ -2927,7 +2927,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -2942,7 +2942,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -2988,7 +2988,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -2996,7 +2996,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -3020,7 +3020,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') if ($cursor) { $documentId = $cursor->getValue(); - $cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); if ($cursorDocument->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Document '{$documentId}' for the 'cursor' value not found."); @@ -3050,7 +3050,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3066,7 +3066,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); - $relatedCollection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)); + $relatedCollection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)); foreach ($relations as $index => $doc) { if ($doc instanceof Document) { @@ -3145,7 +3145,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('dbForProject') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -3154,7 +3154,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -3184,7 +3184,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3199,7 +3199,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3237,7 +3237,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->inject('geodb') ->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); if ($database->isEmpty()) { throw new Exception(Exception::DATABASE_NOT_FOUND); @@ -3357,7 +3357,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD); } - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -3366,7 +3366,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -3374,7 +3374,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum // Read permission should not be required for update /** @var Document $document */ - $document = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); + $document = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3419,7 +3419,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $setCollection = (function (Document $collection, Document $document) use (&$setCollection, $dbForProject, $database) { $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3439,7 +3439,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($relations as &$relation) { @@ -3453,7 +3453,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relation = new Document($relation); } if ($relation instanceof Document) { - $oldDocument = Authorization::skip(fn() => $dbForProject->getDocument( + $oldDocument = Authorization::skip(fn () => $dbForProject->getDocument( 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId() )); @@ -3487,7 +3487,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum try { $document = $dbForProject->withRequestTimestamp( $requestTimestamp, - fn() => $dbForProject->updateDocument( + fn () => $dbForProject->updateDocument( 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document->getId(), $newDocument @@ -3508,7 +3508,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3523,7 +3523,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3576,7 +3576,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->inject('queueForEvents') ->inject('mode') ->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, string $mode) { - $database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId)); + $database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -3585,14 +3585,14 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu throw new Exception(Exception::DATABASE_NOT_FOUND); } - $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); + $collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) { throw new Exception(Exception::COLLECTION_NOT_FOUND); } // Read permission should not be required for delete - $document = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); + $document = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId)); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3618,7 +3618,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $relationships = \array_filter( $collection->getAttribute('attributes', []), - fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP + fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ); foreach ($relationships as $relationship) { @@ -3633,7 +3633,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu $relatedCollectionId = $relationship->getAttribute('relatedCollection'); $relatedCollection = Authorization::skip( - fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) + fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); foreach ($related as $relation) { @@ -3715,19 +3715,19 @@ App::get('/v1/databases/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, 'databasesTotal' => $usage[$metrics[0]]['total'], @@ -3799,19 +3799,19 @@ App::get('/v1/databases/:databaseId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, @@ -3840,9 +3840,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') ->inject('dbForProject') ->action(function (string $databaseId, string $range, string $collectionId, Response $response, Database $dbForProject) { - $database = $dbForProject->getDocument('databases', $databaseId); - $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); - $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId()); + $database = $dbForProject->getDocument('databases', $databaseId); + $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); + $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId()); if ($collection->isEmpty()) { throw new Exception(Exception::COLLECTION_NOT_FOUND); @@ -3885,19 +3885,19 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 0de6f28d57..e4b353dd0d 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -8,44 +8,44 @@ use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Usage; use Appwrite\Event\Validator\FunctionEvent; -use Appwrite\Utopia\Response\Model\Rule; use Appwrite\Extend\Exception; -use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Messaging\Adapter\Realtime; +use Appwrite\Task\Validator\Cron; +use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\Queries\Deployments; +use Appwrite\Utopia\Database\Validator\Queries\Executions; +use Appwrite\Utopia\Database\Validator\Queries\Functions; +use Appwrite\Utopia\Response; +use Appwrite\Utopia\Response\Model\Rule; +use Executor\Executor; +use MaxMind\Db\Reader; +use Utopia\App; +use Utopia\CLI\Console; +use Utopia\Config\Config; +use Utopia\Database\Database; +use Utopia\Database\DateTime; +use Utopia\Database\Document; +use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Query as QueryException; -use Utopia\Validator\Assoc; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Roles; use Utopia\Database\Validator\UID; use Utopia\Storage\Device; use Utopia\Storage\Validator\File; use Utopia\Storage\Validator\FileExt; use Utopia\Storage\Validator\FileSize; use Utopia\Storage\Validator\Upload; -use Appwrite\Utopia\Response; use Utopia\Swoole\Request; -use Appwrite\Task\Validator\Cron; -use Appwrite\Utopia\Database\Validator\Queries\Deployments; -use Appwrite\Utopia\Database\Validator\Queries\Executions; -use Appwrite\Utopia\Database\Validator\Queries\Functions; -use Utopia\App; -use Utopia\Database\Database; -use Utopia\Database\Document; -use Utopia\Database\DateTime; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Validator\ArrayList; -use Utopia\Validator\Text; -use Utopia\Validator\Range; -use Utopia\Validator\WhiteList; -use Utopia\Config\Config; -use Executor\Executor; -use Utopia\CLI\Console; -use Utopia\Database\Validator\Roles; +use Utopia\Validator\Assoc; use Utopia\Validator\Boolean; -use Utopia\Database\Exception\Duplicate as DuplicateException; -use MaxMind\Db\Reader; +use Utopia\Validator\Range; +use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; use Utopia\VCS\Adapter\Git\GitHub; use Utopia\VCS\Exception\RepositoryNotFound; @@ -529,19 +529,19 @@ App::get('/v1/functions/:functionId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, @@ -621,19 +621,19 @@ App::get('/v1/functions/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, 'functionsTotal' => $usage[$metrics[0]]['total'], diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 2749013411..a028b0b59d 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -659,6 +659,60 @@ App::get('/v1/health/queue/functions') $response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); +App::get('/v1/health/queue/usage') + ->desc('Get usage queue') + ->groups(['api', 'health']) + ->label('scope', 'health.read') + ->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') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) + ->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true) + ->inject('queue') + ->inject('response') + ->action(function (int|string $threshold, Connection $queue, Response $response) { + $threshold = \intval($threshold); + + $client = new Client(Event::USAGE_QUEUE_NAME, $queue); + $size = $client->getQueueSize(); + + if ($size >= $threshold) { + throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}."); + } + + $response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE); + }); + +App::get('/v1/health/queue/usage-dump') + ->desc('Get usage dump queue') + ->groups(['api', 'health']) + ->label('scope', 'health.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'health') + ->label('sdk.method', 'getQueueUsage') + ->label('sdk.description', '/docs/references/health/get-queue-usage-dump.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) + ->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true) + ->inject('queue') + ->inject('response') + ->action(function (int|string $threshold, Connection $queue, Response $response) { + $threshold = \intval($threshold); + + $client = new Client(Event::USAGE_DUMP_QUEUE_NAME, $queue); + $size = $client->getQueueSize(); + + if ($size >= $threshold) { + throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}."); + } + + $response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE); + }); + App::get('/v1/health/storage/local') ->desc('Get local storage') ->groups(['api', 'health']) @@ -796,6 +850,7 @@ App::get('/v1/health/queue/failed/:name') Event::MAILS_QUEUE_NAME, Event::FUNCTIONS_QUEUE_NAME, Event::USAGE_QUEUE_NAME, + Event::USAGE_DUMP_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME, Event::CERTIFICATES_QUEUE_NAME, Event::BUILDS_QUEUE_NAME, diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 53f0c5bb25..abb47ab3c4 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -1,7 +1,7 @@ getId()}/files/{$file->getId()}/view?project={$project->getId()}"; + $image = [ + 'bucketId' => $bucket->getId(), + 'fileId' => $file->getId(), + 'url' => "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}", + ]; } $pushData = []; @@ -3771,7 +3774,11 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC); } - $pushData['image'] = "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}"; + $pushData['image'] = [ + 'bucketId' => $bucket->getId(), + 'fileId' => $file->getId(), + 'url' => "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}" + ]; } $message->setAttribute('data', $pushData); diff --git a/app/controllers/api/migrations.php b/app/controllers/api/migrations.php index 455c66061c..0831a473cb 100644 --- a/app/controllers/api/migrations.php +++ b/app/controllers/api/migrations.php @@ -1,7 +1,6 @@ format($format); $metrics = [ - 'total' => [ + 'total' => [ METRIC_EXECUTIONS, METRIC_DOCUMENTS, METRIC_DATABASES, METRIC_USERS, METRIC_BUCKETS, METRIC_FILES_STORAGE - ], - 'period' => [ + ], + 'period' => [ METRIC_NETWORK_REQUESTS, METRIC_NETWORK_INBOUND, METRIC_NETWORK_OUTBOUND, METRIC_USERS, METRIC_EXECUTIONS - ] + ] ]; $factor = match ($period) { diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index d0acdbe15e..0574f9c57b 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1,49 +1,48 @@ desc('Create bucket') @@ -636,7 +635,7 @@ App::post('/v1/storage/buckets/:bucketId/files') if (!$validator->isValid($bucket->getCreate())) { throw new Exception(Exception::USER_UNAUTHORIZED); } - $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); @@ -683,7 +682,7 @@ App::post('/v1/storage/buckets/:bucketId/files') if (!$validator->isValid($bucket->getCreate())) { throw new Exception(Exception::USER_UNAUTHORIZED); } - $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); @@ -766,7 +765,7 @@ App::get('/v1/storage/buckets/:bucketId/files') if ($fileSecurity && !$valid) { $cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($cursorDocument->isEmpty()) { @@ -829,7 +828,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -899,7 +898,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -1055,7 +1054,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -1194,7 +1193,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') if ($fileSecurity && !$valid) { $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if ($file->isEmpty()) { @@ -1353,7 +1352,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') } // Read permission should not be required for update - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1404,7 +1403,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception(Exception::USER_UNAUTHORIZED); } } else { - $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); + $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } $queueForEvents @@ -1458,7 +1457,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') } // Read permission should not be required for delete - $file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId)); if ($file->isEmpty()) { throw new Exception(Exception::STORAGE_FILE_NOT_FOUND); @@ -1482,6 +1481,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($deviceDeleted) { $queueForDeletes ->setType(DELETE_TYPE_CACHE_BY_RESOURCE) + ->setResourceType('bucket/' . $bucket->getId()) ->setResource('file/' . $fileId) ; @@ -1492,7 +1492,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') throw new Exception(Exception::USER_UNAUTHORIZED); } } else { - $deleted = Authorization::skip(fn() => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId)); + $deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId)); } if (!$deleted) { @@ -1567,19 +1567,19 @@ App::get('/v1/storage/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, 'bucketsTotal' => $usage[$metrics[0]]['total'], @@ -1653,19 +1653,19 @@ App::get('/v1/storage/:bucketId/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 5591f307aa..5d13fcfa6e 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -10,15 +10,10 @@ use Appwrite\Event\Mail; use Appwrite\Event\Messaging; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; -use Utopia\Database\Exception\Query as QueryException; -use Utopia\Validator\Host; use Appwrite\Template\Template; use Appwrite\Utopia\Database\Validator\CustomId; -use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Memberships; use Appwrite\Utopia\Database\Validator\Queries\Teams; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use MaxMind\Db\Reader; @@ -26,20 +21,25 @@ use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; -use Utopia\Database\Query; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; +use Utopia\Validator\Host; use Utopia\Validator\Text; App::post('/v1/teams') @@ -71,7 +71,7 @@ App::post('/v1/teams') $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; try { - $team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([ + $team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([ '$id' => $teamId, '$permissions' => [ Permission::read(Role::team($teamId)), @@ -386,7 +386,7 @@ App::post('/v1/teams/:teamId/memberships') ->param('userId', '', new UID(), 'ID of the user to be added to a team.', true) ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') - ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page + ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page ->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true) ->inject('response') ->inject('project') @@ -470,7 +470,7 @@ App::post('/v1/teams/:teamId/memberships') try { $userId = ID::unique(); - $invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([ + $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ '$id' => $userId, '$permissions' => [ Permission::read(Role::any()), @@ -538,12 +538,12 @@ App::post('/v1/teams/:teamId/memberships') if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership try { - $membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership)); + $membership = Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)); } catch (Duplicate $th) { throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS); } - Authorization::skip(fn() => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); $dbForProject->purgeCachedDocument('users', $invitee->getId()); } else { @@ -752,7 +752,7 @@ App::get('/v1/teams/:teamId/memberships') max: APP_LIMIT_COUNT ); - $memberships = array_filter($memberships, fn(Document $membership) => !empty($membership->getAttribute('userId'))); + $memberships = array_filter($memberships, fn (Document $membership) => !empty($membership->getAttribute('userId'))); $memberships = array_map(function ($membership) use ($dbForProject, $team) { $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); @@ -951,7 +951,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH); } - $team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId)); + $team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); @@ -982,7 +982,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->setAttribute('confirm', true) ; - Authorization::skip(fn() => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); + Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); // Log user in @@ -1022,7 +1022,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $dbForProject->purgeCachedDocument('users', $user->getId()); - Authorization::skip(fn() => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1)); $queueForEvents ->setParam('teamId', $team->getId()) @@ -1102,7 +1102,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $dbForProject->purgeCachedDocument('users', $user->getId()); if ($membership->getAttribute('confirm')) { // Count only confirmed members - Authorization::skip(fn() => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); + Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); } $queueForEvents diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 8976510001..46aef57057 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -4,48 +4,48 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\MFA\Type; use Appwrite\Auth\MFA\Type\TOTP; use Appwrite\Auth\Validator\Password; +use Appwrite\Auth\Validator\PasswordDictionary; +use Appwrite\Auth\Validator\PasswordHistory; +use Appwrite\Auth\Validator\PersonalData; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; +use Appwrite\Extend\Exception; +use Appwrite\Hooks\Hooks; use Appwrite\Network\Validator\Email; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Identities; use Appwrite\Utopia\Database\Validator\Queries\Targets; -use Utopia\Database\Exception\Query as QueryException; -use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Users; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; +use MaxMind\Db\Reader; use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; +use Utopia\Database\Database; +use Utopia\Database\DateTime; +use Utopia\Database\Document; +use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Locale\Locale; -use Appwrite\Extend\Exception; -use Utopia\Database\Document; -use Utopia\Database\DateTime; -use Utopia\Database\Exception\Duplicate; -use Utopia\Database\Validator\UID; -use Utopia\Database\Database; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; +use Utopia\Database\Validator\UID; +use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\WhiteList; -use Utopia\Validator\Text; use Utopia\Validator\Boolean; -use Utopia\Validator\Range; -use MaxMind\Db\Reader; use Utopia\Validator\Integer; -use Appwrite\Auth\Validator\PasswordHistory; -use Appwrite\Auth\Validator\PasswordDictionary; -use Appwrite\Auth\Validator\PersonalData; -use Appwrite\Hooks\Hooks; +use Utopia\Validator\Range; +use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; /** TODO: Remove function when we move to using utopia/platform */ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $queueForEvents, Hooks $hooks): Document @@ -813,6 +813,9 @@ App::get('/v1/users/:userId/logs') $output[$i] = new Document([ 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, 'ip' => $log['ip'], 'time' => $log['time'], 'osCode' => $os['osCode'], @@ -841,7 +844,7 @@ App::get('/v1/users/:userId/logs') } $response->dynamic(new Document([ - 'total' => $audit->countLogsByUser($user->getId()), + 'total' => $audit->countLogsByUser($user->getInternalId()), 'logs' => $output, ]), Response::MODEL_LOG_LIST); }); @@ -2150,19 +2153,19 @@ App::get('/v1/users/usage') '1d' => 'Y-m-d\T00:00:00.000P', }; - foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; - $usage[$metric]['data'] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric]['data'][] = [ - 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, - 'date' => $formatDate, - ]; + foreach ($metrics as $metric) { + $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['data'] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric]['data'][] = [ + 'value' => $stats[$metric]['data'][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - } $response->dynamic(new Document([ 'range' => $range, diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 09ec5d7690..ea30d6b11d 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -1,23 +1,20 @@ setStatusCode(404)->send('Not Found'); } - $requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); + $requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', null)); if ($requestFormat) { - switch ($requestFormat) { - case version_compare($requestFormat, '0.12.0', '<'): - Request::setFilter(new RequestV12()); - break; - case version_compare($requestFormat, '0.13.0', '<'): - Request::setFilter(new RequestV13()); - break; - case version_compare($requestFormat, '0.14.0', '<'): - Request::setFilter(new RequestV14()); - break; - case version_compare($requestFormat, '0.15.3', '<'): - Request::setFilter(new RequestV15()); - break; - case version_compare($requestFormat, '1.4.0', '<'): - Request::setFilter(new RequestV16()); - break; - case version_compare($requestFormat, '1.5.0', '<'): - Request::setFilter(new RequestV17()); - break; - default: - Request::setFilter(null); + if (version_compare($requestFormat, '1.4.0', '<')) { + $request->addFilter(new RequestV16()); + } + if (version_compare($requestFormat, '1.5.0', '<')) { + $request->addFilter(new RequestV17()); } - } else { - Request::setFilter(null); } $domain = $request->getHostname(); @@ -529,7 +502,8 @@ App::init() 'cookieDomain', $isLocalHost || $isIpAddress ? null - : ($isConsoleProject && $isConsoleRootSession + : ( + $isConsoleProject && $isConsoleRootSession ? '.' . $selfDomain->getRegisterable() : '.' . $request->getHostname() ) @@ -538,35 +512,14 @@ App::init() /* * Response format */ - $responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); + $responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', null)); if ($responseFormat) { - switch ($responseFormat) { - case version_compare($responseFormat, '0.11.2', '<='): - Response::setFilter(new ResponseV11()); - break; - case version_compare($responseFormat, '0.12.4', '<='): - Response::setFilter(new ResponseV12()); - break; - case version_compare($responseFormat, '0.13.4', '<='): - Response::setFilter(new ResponseV13()); - break; - case version_compare($responseFormat, '0.14.0', '<='): - Response::setFilter(new ResponseV14()); - break; - case version_compare($responseFormat, '0.15.3', '<='): - Response::setFilter(new ResponseV15()); - break; - case version_compare($responseFormat, '1.4.0', '<'): - Response::setFilter(new ResponseV16()); - break; - case version_compare($responseFormat, '1.5.0', '<'): - Response::setFilter(new ResponseV17()); - break; - default: - Response::setFilter(null); + if (version_compare($responseFormat, '1.4.0', '<')) { + $response->addFilter(new ResponseV16()); + } + if (version_compare($responseFormat, '1.5.0', '<')) { + $response->addFilter(new ResponseV17()); } - } else { - Response::setFilter(null); } /* diff --git a/app/controllers/mock.php b/app/controllers/mock.php index fc168ead26..f933c62e6e 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -3,19 +3,19 @@ global $utopia, $request, $response; use Appwrite\Extend\Exception; -use Utopia\Database\Document; -use Utopia\Validator\Host; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\App; use Utopia\Database\Database; -use Utopia\Validator\Text; -use Utopia\Validator\WhiteList; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; -use Utopia\Database\Validator\UID; -use Utopia\VCS\Adapter\Git\GitHub; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\UID; +use Utopia\Validator\Host; +use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; +use Utopia\VCS\Adapter\Git\GitHub; App::get('/v1/mock/tests/general/oauth2') ->desc('OAuth Login') diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f8d2a351ba..d55c085f70 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -9,22 +9,22 @@ use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Messaging; -use Appwrite\Extend\Exception; use Appwrite\Event\Usage; +use Appwrite\Extend\Exception; use Appwrite\Messaging\Adapter\Realtime; -use Appwrite\Utopia\Response; use Appwrite\Utopia\Request; -use Utopia\App; +use Appwrite\Utopia\Response; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; +use Utopia\App; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; +use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; -use Utopia\Config\Config; use Utopia\Database\Helpers\Role; +use Utopia\Database\Validator\Authorization; use Utopia\Validator\WhiteList; $parseLabel = function (string $label, array $responsePayload, array $requestParams, Document $user) { @@ -404,24 +404,22 @@ App::init() ; $useCache = $route->getLabel('cache', false); - if ($useCache) { $key = md5($request->getURI() . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER); + $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $cache = new Cache( new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); $timestamp = 60 * 60 * 24 * 30; $data = $cache->load($key, $timestamp); - if (!empty($data)) { - $data = json_decode($data, true); - $parts = explode('/', $data['resourceType']); + if (!empty($data) && !$cacheLog->isEmpty()) { + $parts = explode('/', $cacheLog->getAttribute('resourceType')); $type = $parts[0] ?? null; if ($type === 'bucket') { $bucketId = $parts[1] ?? null; - - $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); + $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -433,11 +431,12 @@ App::init() $fileSecurity = $bucket->getAttribute('fileSecurity', false); $validator = new Authorization(Database::PERMISSION_READ); $valid = $validator->isValid($bucket->getRead()); + if (!$fileSecurity && !$valid) { throw new Exception(Exception::USER_UNAUTHORIZED); } - $parts = explode('/', $data['resource']); + $parts = explode('/', $cacheLog->getAttribute('resource')); $fileId = $parts[1] ?? null; if ($fileSecurity && !$valid) { @@ -454,8 +453,8 @@ App::init() $response ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT') ->addHeader('X-Appwrite-Cache', 'hit') - ->setContentType($data['contentType']) - ->send(base64_decode($data['payload'])) + ->setContentType($cacheLog->getAttribute('mimeType')) + ->send($data) ; } else { $response->addHeader('X-Appwrite-Cache', 'miss'); @@ -651,7 +650,6 @@ App::shutdown() if ($useCache) { $resource = $resourceType = null; $data = $response->getPayload(); - if (!empty($data['payload'])) { $pattern = $route->getLabel('cache.resource', null); if (!empty($pattern)) { @@ -663,24 +661,19 @@ App::shutdown() $resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user); } - $key = md5($request->getURI() . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER); - $data = json_encode([ - 'resourceType' => $resourceType, - 'resource' => $resource, - 'contentType' => $response->getContentType(), - 'payload' => base64_encode($data['payload']), - ]) ; - - $signature = md5($data); - $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); + $key = md5($request->getURI() . '*' . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER; + $signature = md5($data['payload']); + $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $accessedAt = $cacheLog->getAttribute('accessedAt', ''); $now = DateTime::now(); if ($cacheLog->isEmpty()) { Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([ - '$id' => $key, - 'resource' => $resource, - 'accessedAt' => $now, - 'signature' => $signature, + '$id' => $key, + 'resource' => $resource, + 'resourceType' => $resourceType, + 'mimeType' => $response->getContentType(), + 'accessedAt' => $now, + 'signature' => $signature, ]))); } elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) { $cacheLog->setAttribute('accessedAt', $now); @@ -691,7 +684,7 @@ App::shutdown() $cache = new Cache( new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId()) ); - $cache->save($key, $data); + $cache->save($key, $data['payload']); } } } diff --git a/app/controllers/shared/api/auth.php b/app/controllers/shared/api/auth.php index 2f436a1436..7f304454be 100644 --- a/app/controllers/shared/api/auth.php +++ b/app/controllers/shared/api/auth.php @@ -1,13 +1,13 @@ groups(['mfaProtected']) diff --git a/app/http.php b/app/http.php index 086260cb62..ddf25dd744 100644 --- a/app/http.php +++ b/app/http.php @@ -2,28 +2,28 @@ require_once __DIR__ . '/../vendor/autoload.php'; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Swoole\Constant; -use Swoole\Process; -use Swoole\Http\Server; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; +use Swoole\Http\Server; +use Swoole\Process; +use Utopia\Abuse\Adapters\TimeLimit; use Utopia\App; +use Utopia\Audit\Audit; use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use Utopia\Audit\Audit; -use Utopia\Abuse\Adapters\TimeLimit; -use Utopia\Database\Database; -use Utopia\Database\Document; -use Utopia\Swoole\Files; -use Appwrite\Utopia\Request; use Utopia\Logger\Log; use Utopia\Logger\Log\User; use Utopia\Pools\Group; +use Utopia\Swoole\Files; $http = new Server( host: "0.0.0.0", diff --git a/app/init.php b/app/init.php index c7c07c5501..5f8b0f3030 100644 --- a/app/init.php +++ b/app/init.php @@ -18,38 +18,56 @@ ini_set('display_startup_errors', 1); ini_set('default_socket_timeout', -1); error_reporting(E_ALL); +use Ahc\Jwt\JWT; +use Ahc\Jwt\JWTException; +use Appwrite\Auth\Auth; +use Appwrite\Event\Audit; +use Appwrite\Event\Build; +use Appwrite\Event\Certificate; +use Appwrite\Event\Database as EventDatabase; +use Appwrite\Event\Delete; +use Appwrite\Event\Event; +use Appwrite\Event\Func; +use Appwrite\Event\Mail; +use Appwrite\Event\Messaging; use Appwrite\Event\Migration; use Appwrite\Event\Usage; use Appwrite\Extend\Exception; -use Appwrite\Auth\Auth; -use Appwrite\Event\Audit; -use Appwrite\Event\Database as EventDatabase; -use Appwrite\Event\Event; -use Appwrite\Event\Mail; -use Appwrite\Event\Messaging; -use Appwrite\Event\Delete; +use Appwrite\GraphQL\Promises\Adapter\Swoole; use Appwrite\GraphQL\Schema; +use Appwrite\Hooks\Hooks; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\OpenSSL\OpenSSL; use Appwrite\URL\URL as AppwriteURL; +use MaxMind\Db\Reader; +use PHPMailer\PHPMailer\PHPMailer; +use Swoole\Database\PDOProxy; use Utopia\App; -use Utopia\Database\Adapter\SQL; -use Utopia\Database\Exception\Query as QueryException; -use Utopia\Logger\Logger; use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\Database\Helpers\ID; +use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Adapter\MySQL; +use Utopia\Database\Adapter\SQL; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\Structure; -use Utopia\Locale\Locale; +use Utopia\Domains\Validator\PublicDomain; use Utopia\DSN\DSN; -use Appwrite\GraphQL\Promises\Adapter\Swoole; +use Utopia\Locale\Locale; +use Utopia\Logger\Log; +use Utopia\Logger\Logger; +use Utopia\Pools\Group; +use Utopia\Pools\Pool; +use Utopia\Queue; +use Utopia\Queue\Connection; use Utopia\Registry\Registry; use Utopia\Storage\Device; use Utopia\Storage\Device\Backblaze; @@ -58,32 +76,13 @@ use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; use Utopia\Storage\Device\Wasabi; -use Utopia\Cache\Adapter\Sharding; -use Utopia\Database\Adapter\MariaDB; -use Utopia\Database\Adapter\MySQL; -use Utopia\Pools\Group; -use Utopia\Pools\Pool; -use Ahc\Jwt\JWT; -use Ahc\Jwt\JWTException; -use Appwrite\Event\Build; -use Appwrite\Event\Certificate; -use Appwrite\Event\Func; -use Appwrite\Hooks\Hooks; -use MaxMind\Db\Reader; -use PHPMailer\PHPMailer\PHPMailer; -use Swoole\Database\PDOProxy; -use Utopia\Logger\Log; -use Utopia\Queue; -use Utopia\Queue\Connection; use Utopia\Storage\Storage; -use Utopia\VCS\Adapter\Git\GitHub as VcsGitHub; -use Utopia\Validator\Range; use Utopia\Validator\Hostname; use Utopia\Validator\IP; +use Utopia\Validator\Range; use Utopia\Validator\URL; use Utopia\Validator\WhiteList; -use Utopia\CLI\Console; -use Utopia\Domains\Validator\PublicDomain; +use Utopia\VCS\Adapter\Git\GitHub as VcsGitHub; const APP_NAME = 'Appwrite'; const APP_DOMAIN = 'appwrite.io'; @@ -296,7 +295,7 @@ Database::addFilter( }, function (mixed $value) { if (is_null($value)) { - return null; + return; } return json_decode($value, true)['value']; @@ -350,7 +349,7 @@ Database::addFilter( Database::addFilter( 'subQueryAttributes', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { $attributes = $database->find('attributes', [ @@ -376,7 +375,7 @@ Database::addFilter( Database::addFilter( 'subQueryIndexes', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return $database @@ -391,7 +390,7 @@ Database::addFilter( Database::addFilter( 'subQueryPlatforms', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return $database @@ -405,7 +404,7 @@ Database::addFilter( Database::addFilter( 'subQueryKeys', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return $database @@ -419,7 +418,7 @@ Database::addFilter( Database::addFilter( 'subQueryWebhooks', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return $database @@ -433,7 +432,7 @@ Database::addFilter( Database::addFilter( 'subQuerySessions', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return Authorization::skip(fn () => $database->find('sessions', [ @@ -446,10 +445,10 @@ Database::addFilter( Database::addFilter( 'subQueryTokens', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('tokens', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -460,10 +459,10 @@ Database::addFilter( Database::addFilter( 'subQueryChallenges', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('challenges', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -474,10 +473,10 @@ Database::addFilter( Database::addFilter( 'subQueryAuthenticators', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('authenticators', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -488,10 +487,10 @@ Database::addFilter( Database::addFilter( 'subQueryMemberships', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('memberships', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY), @@ -502,7 +501,7 @@ Database::addFilter( Database::addFilter( 'subQueryVariables', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return $database @@ -531,7 +530,7 @@ Database::addFilter( }, function (mixed $value) { if (is_null($value)) { - return null; + return; } $value = json_decode($value, true); $key = App::getEnv('_APP_OPENSSL_KEY_V' . $value['version']); @@ -543,7 +542,7 @@ Database::addFilter( Database::addFilter( 'subQueryProjectVariables', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { return $database @@ -580,10 +579,10 @@ Database::addFilter( Database::addFilter( 'subQueryTargets', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { - return Authorization::skip(fn() => $database + return Authorization::skip(fn () => $database ->find('targets', [ Query::equal('userInternalId', [$document->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY) @@ -594,7 +593,7 @@ Database::addFilter( Database::addFilter( 'subQueryTopicTargets', function (mixed $value) { - return null; + return; }, function (mixed $value, Document $document, Database $database) { $targetIds = Authorization::skip(fn () => \array_map( @@ -724,7 +723,7 @@ $register->set('logger', function () { $providerConfig = App::getEnv('_APP_LOGGING_CONFIG', ''); if (empty($providerName) || empty($providerConfig)) { - return null; + return; } if (!Logger::hasProvider($providerName)) { @@ -1011,7 +1010,7 @@ foreach ($locales as $locale) { ]); // Runtime Execution -App::setResource('log', fn() => new Log()); +App::setResource('log', fn () => new Log()); App::setResource('logger', function ($register) { return $register->get('logger'); }, ['register']); @@ -1020,11 +1019,11 @@ App::setResource('hooks', function ($register) { return $register->get('hooks'); }, ['register']); -App::setResource('register', fn() => $register); -App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en'))); +App::setResource('register', fn () => $register); +App::setResource('locale', fn () => new Locale(App::getEnv('_APP_LOCALE', 'en'))); App::setResource('localeCodes', function () { - return array_map(fn($locale) => $locale['code'], Config::getParam('locale-codes', [])); + return array_map(fn ($locale) => $locale['code'], Config::getParam('locale-codes', [])); }); // Queues @@ -1233,14 +1232,14 @@ App::setResource('project', function ($dbForConsole, $request, $console) { return $console; } - $project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId)); return $project; }, ['dbForConsole', 'request', 'console']); App::setResource('session', function (Document $user, Document $project) { if ($user->isEmpty()) { - return null; + return; } $sessions = $user->getAttribute('sessions', []); @@ -1248,7 +1247,7 @@ App::setResource('session', function (Document $user, Document $project) { $sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret, $authDuration); if (!$sessionId) { - return null; + return; } foreach ($sessions as $session) {/** @var Document $session */ @@ -1257,7 +1256,7 @@ App::setResource('session', function (Document $user, Document $project) { } } - return null; + return; }, ['user', 'project']); App::setResource('console', function () { @@ -1543,7 +1542,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { }; $attributes = function (int $limit, int $offset) use ($dbForProject) { - $attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [ + $attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [ Query::limit($limit), Query::offset($offset), ])); diff --git a/app/realtime.php b/app/realtime.php index 663e8c9e7f..fd7d69bbf5 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -14,20 +14,20 @@ use Swoole\Timer; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; use Utopia\App; -use Utopia\CLI\Console; -use Utopia\Database\Helpers\ID; -use Utopia\Database\Helpers\Role; -use Utopia\Logger\Log; -use Utopia\Database\DateTime; -use Utopia\Database\Document; -use Utopia\Database\Query; -use Utopia\Database\Validator\Authorization; use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\WebSocket\Server; +use Utopia\Database\DateTime; +use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; +use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Logger\Log; use Utopia\WebSocket\Adapter; +use Utopia\WebSocket\Server; /** * @var \Utopia\Registry\Registry $register @@ -340,7 +340,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); $consoleDatabase = getConsoleDB(); - $project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId)); $database = getProjectDB($project); $user = $database->getDocument('users', $userId); @@ -395,9 +395,9 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, Console::info("Connection open (user: {$connection})"); - App::setResource('pools', fn() => $register->get('pools')); - App::setResource('request', fn() => $request); - App::setResource('response', fn() => $response); + App::setResource('pools', fn () => $register->get('pools')); + App::setResource('request', fn () => $request); + App::setResource('response', fn () => $response); try { /** @var Document $project */ @@ -502,7 +502,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $database = getConsoleDB(); if ($projectId !== 'console') { - $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); + $project = Authorization::skip(fn () => $database->getDocument('projects', $projectId)); $database = getProjectDB($project); } else { $project = null; diff --git a/app/worker.php b/app/worker.php index f29e8ade62..98a1e40a88 100644 --- a/app/worker.php +++ b/app/worker.php @@ -2,18 +2,17 @@ require_once __DIR__ . '/init.php'; -use Appwrite\Event\Event; use Appwrite\Event\Audit; use Appwrite\Event\Build; use Appwrite\Event\Certificate; use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Delete; +use Appwrite\Event\Event; use Appwrite\Event\Func; use Appwrite\Event\Hamster; use Appwrite\Event\Mail; use Appwrite\Event\Messaging; use Appwrite\Event\Migration; -use Appwrite\Event\Phone; use Appwrite\Event\Usage; use Appwrite\Event\UsageDump; use Appwrite\Platform\Appwrite; @@ -27,14 +26,14 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; +use Utopia\Logger\Log; +use Utopia\Logger\Logger; use Utopia\Platform\Service; +use Utopia\Pools\Group; +use Utopia\Queue\Connection; use Utopia\Queue\Message; use Utopia\Queue\Server; use Utopia\Registry\Registry; -use Utopia\Logger\Log; -use Utopia\Logger\Logger; -use Utopia\Pools\Group; -use Utopia\Queue\Connection; use Utopia\Storage\Device\Local; Authorization::disable(); @@ -141,7 +140,7 @@ Server::setResource('cache', function (Registry $register) { return new Cache(new Sharding($adapters)); }, ['register']); -Server::setResource('log', fn() => new Log()); +Server::setResource('log', fn () => new Log()); Server::setResource('queueForUsage', function (Connection $queue) { return new Usage($queue); diff --git a/composer.json b/composer.json index 28dbde65be..8d1cc0bd7d 100644 --- a/composer.json +++ b/composer.json @@ -12,8 +12,8 @@ ], "scripts": { "test": "vendor/bin/phpunit", - "lint": "vendor/bin/phpcs", - "format": "vendor/bin/phpcbf" + "lint": "vendor/bin/pint --test", + "format": "vendor/bin/pint" }, "autoload": { "psr-4": { @@ -81,10 +81,10 @@ "ext-fileinfo": "*", "appwrite/sdk-generator": "0.37.0-rc.6", "phpunit/phpunit": "9.5.20", - "squizlabs/php_codesniffer": "^3.7", "swoole/ide-helper": "5.0.2", "textalk/websocket": "1.5.7", - "utopia-php/fetch": "0.1.*" + "utopia-php/fetch": "0.1.*", + "laravel/pint": "^1.14" }, "provide": { "ext-phpiredis": "*" diff --git a/composer.lock b/composer.lock index ae1746ba06..c44a41b254 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "733cdc4128cc298318cf487442d3efed", + "content-hash": "427cda6539f0edab82485bf43a257ad4", "packages": [ { "name": "adhocore/jwt", @@ -2893,6 +2893,72 @@ ], "time": "2022-12-30T00:15:36+00:00" }, + { + "name": "laravel/pint", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/6b127276e3f263f7bb17d5077e9e0269e61b2a0e", + "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.49.0", + "illuminate/view": "^10.43.0", + "larastan/larastan": "^2.8.1", + "laravel-zero/framework": "^10.3.0", + "mockery/mockery": "^1.6.7", + "nunomaduro/termwind": "^1.15.1", + "pestphp/pest": "^2.33.6" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2024-02-20T17:38:05+00:00" + }, { "name": "matthiasmullie/minify", "version": "1.3.71", @@ -3078,16 +3144,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.0.1", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69", - "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { @@ -3130,9 +3196,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2024-02-21T19:24:10+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "phar-io/manifest", @@ -4972,86 +5038,6 @@ ], "time": "2020-09-28T06:39:44+00:00" }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.9.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b", - "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - } - ], - "time": "2024-02-16T15:06:51+00:00" - }, { "name": "swoole/ide-helper", "version": "5.0.2", diff --git a/docker-compose.yml b/docker-compose.yml index b706dc9459..58dff56901 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -971,6 +971,7 @@ services: # - appwrite # volumes: # - appwrite-uploads:/storage/uploads + # Dev Tools Start ------------------------------------------------------------------------------------------ # # The Appwrite Team uses the following tools to help debug, monitor and diagnose the Appwrite stack diff --git a/docs/references/health/get-queue-usage-dump.md b/docs/references/health/get-queue-usage-dump.md new file mode 100644 index 0000000000..3c95da1b8a --- /dev/null +++ b/docs/references/health/get-queue-usage-dump.md @@ -0,0 +1 @@ +Get the number of projects containing metrics that are waiting to be processed in the Appwrite internal queue server. \ No newline at end of file diff --git a/docs/references/health/get-queue-usage.md b/docs/references/health/get-queue-usage.md new file mode 100644 index 0000000000..8e5b64e642 --- /dev/null +++ b/docs/references/health/get-queue-usage.md @@ -0,0 +1 @@ +Get the number of metrics that are waiting to be processed in the Appwrite internal queue server. \ No newline at end of file diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index 70e4df36ed..0000000000 --- a/phpcs.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - ./app - ./src - ./tests - - - ./app/sdks - - ./tests/resources/functions - - ./app/console - - - * - - - - * - - - - ./app - - \ No newline at end of file diff --git a/pint.json b/pint.json new file mode 100644 index 0000000000..14614b0208 --- /dev/null +++ b/pint.json @@ -0,0 +1,21 @@ +{ + "preset": "psr12", + "exclude": [ + "./app/sdks", + "./tests/resources/functions", + "./app/console" + ], + "rules": { + "array_indentation": true, + "single_import_per_statement": true, + "simplified_null_return": true, + "ordered_imports": { + "sort_algorithm": "alpha", + "imports_order": [ + "const", + "class", + "function" + ] + } + } +} diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php index a25c6123ea..1e8109622e 100644 --- a/src/Appwrite/Auth/Auth.php +++ b/src/Appwrite/Auth/Auth.php @@ -9,8 +9,8 @@ use Appwrite\Auth\Hash\Phpass; use Appwrite\Auth\Hash\Scrypt; use Appwrite\Auth\Hash\Scryptmodified; use Appwrite\Auth\Hash\Sha; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; diff --git a/src/Appwrite/Auth/OAuth2/Authentik.php b/src/Appwrite/Auth/OAuth2/Authentik.php index 16822e2c9f..5d2445088b 100644 --- a/src/Appwrite/Auth/OAuth2/Authentik.php +++ b/src/Appwrite/Auth/OAuth2/Authentik.php @@ -171,11 +171,11 @@ class Authentik extends OAuth2 return ''; } - /** - * @param string $accessToken - * - * @return array - */ + /** + * @param string $accessToken + * + * @return array + */ protected function getUser(string $accessToken): array { if (empty($this->user)) { @@ -199,11 +199,11 @@ class Authentik extends OAuth2 return $secret['clientSecret'] ?? ''; } - /** - * Extracts the authentik Domain from the JSON stored in appSecret - * - * @return string - */ + /** + * Extracts the authentik Domain from the JSON stored in appSecret + * + * @return string + */ protected function getAuthentikDomain(): string { $secret = $this->getAppSecret(); diff --git a/src/Appwrite/Auth/OAuth2/Discord.php b/src/Appwrite/Auth/OAuth2/Discord.php index b77ce6a236..a5ecdb5e3c 100644 --- a/src/Appwrite/Auth/OAuth2/Discord.php +++ b/src/Appwrite/Auth/OAuth2/Discord.php @@ -28,8 +28,8 @@ class Discord extends OAuth2 * @var array */ protected array $scopes = [ - 'identify', - 'email' + 'identify', + 'email' ]; /** diff --git a/src/Appwrite/Auth/OAuth2/Mock.php b/src/Appwrite/Auth/OAuth2/Mock.php index d2cb8c1c2a..61ce41d1b7 100644 --- a/src/Appwrite/Auth/OAuth2/Mock.php +++ b/src/Appwrite/Auth/OAuth2/Mock.php @@ -3,7 +3,6 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; -use Utopia\Exception; class Mock extends OAuth2 { diff --git a/src/Appwrite/Auth/OAuth2/Oidc.php b/src/Appwrite/Auth/OAuth2/Oidc.php index de2eab65c8..670169fe89 100644 --- a/src/Appwrite/Auth/OAuth2/Oidc.php +++ b/src/Appwrite/Auth/OAuth2/Oidc.php @@ -168,11 +168,11 @@ class Oidc extends OAuth2 return ''; } - /** - * @param string $accessToken - * - * @return array - */ + /** + * @param string $accessToken + * + * @return array + */ protected function getUser(string $accessToken): array { if (empty($this->user)) { @@ -196,11 +196,11 @@ class Oidc extends OAuth2 return $secret['clientSecret'] ?? ''; } - /** - * Extracts the well known endpoint from the JSON stored in appSecret. - * - * @return string - */ + /** + * Extracts the well known endpoint from the JSON stored in appSecret. + * + * @return string + */ protected function getWellKnownEndpoint(): string { $secret = $this->getAppSecret(); @@ -266,9 +266,9 @@ class Oidc extends OAuth2 return $wellKnownConfiguration['userinfo_endpoint'] ?? ''; } - /** - * Get the well-known configuration using the well known endpoint - */ + /** + * Get the well-known configuration using the well known endpoint + */ protected function getWellKnownConfiguration(): array { if (empty($this->wellKnownConfiguration)) { diff --git a/src/Appwrite/Auth/OAuth2/PaypalSandbox.php b/src/Appwrite/Auth/OAuth2/PaypalSandbox.php index 0f56a09c21..e5ab612c0d 100644 --- a/src/Appwrite/Auth/OAuth2/PaypalSandbox.php +++ b/src/Appwrite/Auth/OAuth2/PaypalSandbox.php @@ -2,8 +2,6 @@ namespace Appwrite\Auth\OAuth2; -use Appwrite\Auth\OAuth2\Paypal; - class PaypalSandbox extends Paypal { protected string $environment = 'sandbox'; diff --git a/src/Appwrite/Auth/OAuth2/Podio.php b/src/Appwrite/Auth/OAuth2/Podio.php index e4194238d1..0b1f35414b 100644 --- a/src/Appwrite/Auth/OAuth2/Podio.php +++ b/src/Appwrite/Auth/OAuth2/Podio.php @@ -148,7 +148,7 @@ class Podio extends OAuth2 $user = $this->getUser($accessToken); $mails = $user['mails']; - $mainMailIndex = \array_search($user['mail'], \array_map(fn($m) => $m['mail'], $mails)); + $mainMailIndex = \array_search($user['mail'], \array_map(fn ($m) => $m['mail'], $mails)); $mainMain = $mails[$mainMailIndex]; if ($mainMain['verified'] ?? false) { diff --git a/src/Appwrite/Auth/OAuth2/Stripe.php b/src/Appwrite/Auth/OAuth2/Stripe.php index 5a959dbfcb..9d1c9206ad 100644 --- a/src/Appwrite/Auth/OAuth2/Stripe.php +++ b/src/Appwrite/Auth/OAuth2/Stripe.php @@ -3,7 +3,6 @@ namespace Appwrite\Auth\OAuth2; use Appwrite\Auth\OAuth2; -use Utopia\Exception; class Stripe extends OAuth2 { diff --git a/src/Appwrite/Auth/OAuth2/TradeshiftBox.php b/src/Appwrite/Auth/OAuth2/TradeshiftBox.php index 27a4c0a456..d960acf2d3 100644 --- a/src/Appwrite/Auth/OAuth2/TradeshiftBox.php +++ b/src/Appwrite/Auth/OAuth2/TradeshiftBox.php @@ -2,8 +2,6 @@ namespace Appwrite\Auth\OAuth2; -use Appwrite\Auth\OAuth2\Tradeshift; - class TradeshiftBox extends Tradeshift { protected string $environment = 'sandbox'; diff --git a/src/Appwrite/Docker/Env.php b/src/Appwrite/Docker/Env.php index bce12a95e6..51ec9e167c 100644 --- a/src/Appwrite/Docker/Env.php +++ b/src/Appwrite/Docker/Env.php @@ -2,8 +2,6 @@ namespace Appwrite\Docker; -use Exception; - class Env { /** diff --git a/src/Appwrite/Event/Delete.php b/src/Appwrite/Event/Delete.php index 57300feb72..064fbcefa9 100644 --- a/src/Appwrite/Event/Delete.php +++ b/src/Appwrite/Event/Delete.php @@ -10,6 +10,7 @@ class Delete extends Event { protected string $type = ''; protected ?Document $document = null; + protected ?string $resourceType = null; protected ?string $resource = null; protected ?string $datetime = null; protected ?string $hourlyUsageRetentionDatetime = null; @@ -107,6 +108,19 @@ class Delete extends Event return $this; } + /** + * Sets the resource type for the delete event. + * + * @param string $resourceType + * @return self + */ + public function setResourceType(string $resourceType): self + { + $this->resourceType = $resourceType; + + return $this; + } + /** * Returns the set document for the delete event. * @@ -133,6 +147,7 @@ class Delete extends Event 'type' => $this->type, 'document' => $this->document, 'resource' => $this->resource, + 'resourceType' => $this->resourceType, 'datetime' => $this->datetime, 'hourlyUsageRetentionDatetime' => $this->hourlyUsageRetentionDatetime ]); diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index 9f71ef5ebc..fa9ddf1315 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -454,9 +454,9 @@ class Event if ($subCurrent === $current || $subCurrent === $key) { continue; } - $filtered1 = \array_filter($paramKeys, fn(string $k) => $k === $subCurrent); + $filtered1 = \array_filter($paramKeys, fn (string $k) => $k === $subCurrent); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered1, '*', $eventPattern)); - $filtered2 = \array_filter($paramKeys, fn(string $k) => $k === $current); + $filtered2 = \array_filter($paramKeys, fn (string $k) => $k === $current); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', \str_replace($filtered1, '*', $eventPattern))); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', $eventPattern)); } @@ -464,7 +464,7 @@ class Event if ($current === $key) { continue; } - $filtered = \array_filter($paramKeys, fn(string $k) => $k === $current); + $filtered = \array_filter($paramKeys, fn (string $k) => $k === $current); $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern)); } } diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php index f8ea9e472b..f97ff02d21 100644 --- a/src/Appwrite/Event/Messaging.php +++ b/src/Appwrite/Event/Messaging.php @@ -3,8 +3,8 @@ namespace Appwrite\Event; use Utopia\Database\Document; -use Utopia\Queue\Connection; use Utopia\Queue\Client; +use Utopia\Queue\Connection; class Messaging extends Event { diff --git a/src/Appwrite/Event/Usage.php b/src/Appwrite/Event/Usage.php index ded276e166..cf92e6ffef 100644 --- a/src/Appwrite/Event/Usage.php +++ b/src/Appwrite/Event/Usage.php @@ -2,10 +2,9 @@ namespace Appwrite\Event; -use Utopia\CLI\Console; +use Utopia\Database\Document; use Utopia\Queue\Client; use Utopia\Queue\Connection; -use Utopia\Database\Document; class Usage extends Event { diff --git a/src/Appwrite/Event/Validator/FunctionEvent.php b/src/Appwrite/Event/Validator/FunctionEvent.php index 6443b127ad..dceb2df1ae 100644 --- a/src/Appwrite/Event/Validator/FunctionEvent.php +++ b/src/Appwrite/Event/Validator/FunctionEvent.php @@ -2,8 +2,6 @@ namespace Appwrite\Event\Validator; -use Utopia\Config\Config; - class FunctionEvent extends Event { /** diff --git a/src/Appwrite/GraphQL/Resolvers.php b/src/Appwrite/GraphQL/Resolvers.php index 37bc1d922b..a1f6af0f3f 100644 --- a/src/Appwrite/GraphQL/Resolvers.php +++ b/src/Appwrite/GraphQL/Resolvers.php @@ -23,7 +23,7 @@ class Resolvers App $utopia, ?Route $route, ): callable { - return static fn($type, $args, $context, $info) => new Swoole( + return static fn ($type, $args, $context, $info) => new Swoole( function (callable $resolve, callable $reject) use ($utopia, $route, $args, $context, $info) { /** @var App $utopia */ /** @var Response $response */ @@ -94,7 +94,7 @@ class Resolvers string $collectionId, callable $url, ): callable { - return static fn($type, $args, $context, $info) => new Swoole( + return static fn ($type, $args, $context, $info) => new Swoole( function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); @@ -125,7 +125,7 @@ class Resolvers callable $url, callable $params, ): callable { - return static fn($type, $args, $context, $info) => new Swoole( + return static fn ($type, $args, $context, $info) => new Swoole( function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); @@ -161,7 +161,7 @@ class Resolvers callable $url, callable $params, ): callable { - return static fn($type, $args, $context, $info) => new Swoole( + return static fn ($type, $args, $context, $info) => new Swoole( function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); @@ -193,7 +193,7 @@ class Resolvers callable $url, callable $params, ): callable { - return static fn($type, $args, $context, $info) => new Swoole( + return static fn ($type, $args, $context, $info) => new Swoole( function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); @@ -223,7 +223,7 @@ class Resolvers string $collectionId, callable $url, ): callable { - return static fn($type, $args, $context, $info) => new Swoole( + return static fn ($type, $args, $context, $info) => new Swoole( function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); @@ -263,7 +263,7 @@ class Resolvers } $request = clone $request; - $utopia->setResource('request', static fn() => $request); + $utopia->setResource('request', static fn () => $request); $response->setContentType(Response::CONTENT_TYPE_NULL); try { diff --git a/src/Appwrite/GraphQL/Schema.php b/src/Appwrite/GraphQL/Schema.php index 11f728e571..833ea9d032 100644 --- a/src/Appwrite/GraphQL/Schema.php +++ b/src/Appwrite/GraphQL/Schema.php @@ -230,7 +230,7 @@ class Schema 'args' => \array_merge( Mapper::args('id'), \array_map( - fn($attr) => $attr['type'] = Type::getNullableType($attr['type']), + fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']), $attributes ) ), diff --git a/src/Appwrite/GraphQL/Types/Assoc.php b/src/Appwrite/GraphQL/Types/Assoc.php index a2099f9b22..f76b23dd7a 100644 --- a/src/Appwrite/GraphQL/Types/Assoc.php +++ b/src/Appwrite/GraphQL/Types/Assoc.php @@ -2,14 +2,7 @@ namespace Appwrite\GraphQL\Types; -use GraphQL\Language\AST\BooleanValueNode; -use GraphQL\Language\AST\FloatValueNode; -use GraphQL\Language\AST\IntValueNode; -use GraphQL\Language\AST\ListValueNode; use GraphQL\Language\AST\Node; -use GraphQL\Language\AST\ObjectValueNode; -use GraphQL\Language\AST\StringValueNode; -use GraphQL\Type\Definition\ScalarType; // https://github.com/webonyx/graphql-php/issues/129#issuecomment-309366803 class Assoc extends Json diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php index 280d094a0c..36b246b28b 100644 --- a/src/Appwrite/GraphQL/Types/Mapper.php +++ b/src/Appwrite/GraphQL/Types/Mapper.php @@ -87,7 +87,7 @@ class Mapper $names = $route->getLabel('sdk.response.model', 'none'); $models = \is_array($names) - ? \array_map(static fn($m) => static::$models[$m], $names) + ? \array_map(static fn ($m) => static::$models[$m], $names) : [static::$models[$names]]; foreach ($models as $model) { @@ -150,7 +150,7 @@ class Mapper 'resolve' => static function ($object, $args, $context, $info) { $data = \array_filter( (array)$object, - fn($key) => !\str_starts_with($key, '_'), + fn ($key) => !\str_starts_with($key, '_'), ARRAY_FILTER_USE_KEY ); @@ -165,7 +165,7 @@ class Mapper $fields['status'] = [ 'type' => Type::string(), 'description' => 'Status', - 'resolve' => static fn($object, $args, $context, $info) => 'OK', + 'resolve' => static fn ($object, $args, $context, $info) => 'OK', ]; } diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index 1925944664..792adfa5a4 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -2,10 +2,10 @@ namespace Appwrite\Messaging\Adapter; -use Utopia\Database\DateTime; -use Utopia\Database\Document; use Appwrite\Messaging\Adapter; use Utopia\App; +use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 4038362720..cbcc7a9322 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -2,15 +2,15 @@ namespace Appwrite\Migration; +use Exception; use Swoole\Runtime; -use Utopia\Database\Document; -use Utopia\Database\Database; -use Utopia\Database\Query; +use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; -use Exception; -use Utopia\App; +use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); diff --git a/src/Appwrite/Migration/Version/V15.php b/src/Appwrite/Migration/Version/V15.php index aaa8fd2373..e2de0422de 100644 --- a/src/Appwrite/Migration/Version/V15.php +++ b/src/Appwrite/Migration/Version/V15.php @@ -4,8 +4,6 @@ namespace Appwrite\Migration\Version; use Appwrite\Migration\Migration; use Appwrite\OpenSSL\OpenSSL; -use Exception; -use PDO; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; @@ -1236,7 +1234,7 @@ class V15 extends Migration * skipping migration for 'cache' and 'variables'. * 'users' already migrated. */ - return null; + return; case '_metadata': /** diff --git a/src/Appwrite/Migration/Version/V17.php b/src/Appwrite/Migration/Version/V17.php index 4bdae76621..96c890c65d 100644 --- a/src/Appwrite/Migration/Version/V17.php +++ b/src/Appwrite/Migration/Version/V17.php @@ -266,9 +266,9 @@ class V17 extends Migration ])); break; case 'users': - /** - * Set hashOptions type - */ + /** + * Set hashOptions type + */ $document->setAttribute('hashOptions', array_merge($document->getAttribute('hashOptions', []), [ 'type' => $document->getAttribute('hash', Auth::DEFAULT_ALGO) ])); diff --git a/src/Appwrite/Migration/Version/V19.php b/src/Appwrite/Migration/Version/V19.php index a92fb0a5fb..7934c1aaa6 100644 --- a/src/Appwrite/Migration/Version/V19.php +++ b/src/Appwrite/Migration/Version/V19.php @@ -650,8 +650,8 @@ class V19 extends Migration { foreach ( $this->documentsIterator('attributes', [ - Query::equal('format', ['enum']), - Query::lessThan('size', Database::LENGTH_KEY) + Query::equal('format', ['enum']), + Query::lessThan('size', Database::LENGTH_KEY) ]) as $attribute ) { $attribute->setAttribute('size', Database::LENGTH_KEY); diff --git a/src/Appwrite/Migration/Version/V20.php b/src/Appwrite/Migration/Version/V20.php index a996fff171..4f547b9234 100644 --- a/src/Appwrite/Migration/Version/V20.php +++ b/src/Appwrite/Migration/Version/V20.php @@ -81,23 +81,29 @@ class V20 extends Migration if ($collectionType === 'projects') { foreach ( $this->documentsIterator('attributes', [ - Query::equal('array', [true]), + Query::equal('array', [true]), ]) as $attribute ) { $foundIndex = false; + $collectionId = "database_{$attribute['databaseInternalId']}_collection_{$attribute['collectionInternalId']}"; foreach ( $this->documentsIterator('indexes', [ Query::equal('databaseInternalId', [$attribute['databaseInternalId']]), Query::equal('collectionInternalId', [$attribute['collectionInternalId']]), ]) as $index ) { - if (in_array($attribute['key'], $index['attributes'])) { - $this->projectDB->deleteIndex($index['collectionId'], $index['$id']); - $foundIndex = true; + if (in_array($attribute->getAttribute('key'), $index->getAttribute('attributes'))) { + try { + $this->projectDB->deleteIndex($collectionId, $index->getId()); + } catch (Throwable $th) { + Console::warning("Failed to delete index: {$th->getMessage()}"); + } finally { + $foundIndex = true; + } } } if ($foundIndex === true) { - $this->projectDB->updateAttribute($attribute['collectionInternalId'], $attribute['key'], $attribute['type']); + $this->projectDB->updateAttribute($collectionId, $attribute['key'], $attribute['type']); } } } @@ -137,11 +143,12 @@ class V20 extends Migration $this->createCollection('authenticators'); break; + case 'cache': + // Create resourceType attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'resourceType'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'resourceType' from {$id}: {$th->getMessage()}"); } @@ -149,10 +156,14 @@ class V20 extends Migration // Create mimeType attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'mimeType'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'mimeType' from {$id}: {$th->getMessage()}"); } + try { + $this->projectDB->purgeCachedCollection($id); + } catch (Throwable $th) { + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); + } break; case 'stats': @@ -165,11 +176,16 @@ class V20 extends Migration * Alter `signed` internal type on `value` attr */ $this->projectDB->updateAttribute(collection: $id, id: 'value', signed: true); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'type' from {$id}: {$th->getMessage()}"); } + try { + $this->projectDB->purgeCachedCollection($id); + } catch (Throwable $th) { + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); + } + // update stats index $index = '_key_metric_period_time'; @@ -190,7 +206,6 @@ class V20 extends Migration // Create expire attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'expire'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'expire' from {$id}: {$th->getMessage()}"); } @@ -198,17 +213,28 @@ class V20 extends Migration // Create factors attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'factors'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'factors' from {$id}: {$th->getMessage()}"); } + // Create mfaRecoveryCodes attribute + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'mfaUpdatedAt'); + } catch (Throwable $th) { + Console::warning("'mfaUpdatedAt' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->purgeCachedCollection($id); + } catch (Throwable $th) { + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); + } + break; case 'users': // Create targets attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'targets'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'targets' from {$id}: {$th->getMessage()}"); } @@ -216,15 +242,20 @@ class V20 extends Migration // Create mfa attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'mfa'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'mfa' from {$id}: {$th->getMessage()}"); } + // Create mfaRecoveryCodes attribute + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'mfaRecoveryCodes'); + } catch (Throwable $th) { + Console::warning("'mfaRecoveryCodes' from {$id}: {$th->getMessage()}"); + } + // Create challenges attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'challenges'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'challenges' from {$id}: {$th->getMessage()}"); } @@ -232,32 +263,60 @@ class V20 extends Migration // Create authenticators attribute try { $this->createAttributeFromCollection($this->projectDB, $id, 'authenticators'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'authenticators' from {$id}: {$th->getMessage()}"); } + try { + $this->projectDB->purgeCachedCollection($id); + } catch (Throwable $th) { + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); + } + break; case 'projects': // Rename providers authProviders to oAuthProviders try { $this->projectDB->renameAttribute($id, 'authProviders', 'oAuthProviders'); - $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { Console::warning("'oAuthProviders' from {$id}: {$th->getMessage()}"); } - break; - case 'webhooks': + try { - $this->createAttributeFromCollection($this->projectDB, $id, 'enabled'); - $this->createAttributeFromCollection($this->projectDB, $id, 'logs'); - $this->createAttributeFromCollection($this->projectDB, $id, 'attempts'); $this->projectDB->purgeCachedCollection($id); } catch (Throwable $th) { - Console::warning("'webhooks' from {$id}: {$th->getMessage()}"); + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); } + break; - default: + case 'webhooks': + // Create enabled attribute + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'enabled'); + } catch (Throwable $th) { + Console::warning("'enabled' from {$id}: {$th->getMessage()}"); + } + + // Create logs attribute + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'logs'); + } catch (Throwable $th) { + Console::warning("'logs' from {$id}: {$th->getMessage()}"); + } + + // Create attempts attribute + try { + $this->createAttributeFromCollection($this->projectDB, $id, 'attempts'); + } catch (Throwable $th) { + Console::warning("'attempts' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->purgeCachedCollection($id); + } catch (Throwable $th) { + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); + } + break; } @@ -265,8 +324,6 @@ class V20 extends Migration } } - - /** * @return void * @throws Authorization @@ -278,7 +335,6 @@ class V20 extends Migration /** * Creating inf metric */ - Console::info('Migrating Sessions metric'); $sessionsCreated = $this->projectDB->sum('stats', 'value', [ @@ -317,7 +373,7 @@ class V20 extends Migration /** * Creating inf metric */ - console::log("Creating inf metric to {$metric}"); + Console::log("Creating inf metric to {$metric}"); $id = \md5("_inf_{$metric}"); $this->projectDB->createDocument('stats', new Document([ '$id' => $id, @@ -328,7 +384,7 @@ class V20 extends Migration 'region' => 'default', ])); } catch (Duplicate $th) { - console::log("Error while creating inf metric: duplicate id {$metric} {$id}"); + Console::warning("Error while creating inf metric: duplicate id {$metric} {$id}"); } } @@ -382,7 +438,7 @@ class V20 extends Migration $stat->setAttribute('$id', \md5("{$time}_{$stat['period']}_{$to}")); $stat->setAttribute('metric', $to); $this->projectDB->createDocument('stats', $stat); - console::log("deleting metric {$from} and creating {$to}"); + Console::log("deleting metric {$from} and creating {$to}"); } $latestDocument = !empty(array_key_last($stats)) ? $stats[array_key_last($stats)] : null; } @@ -508,7 +564,11 @@ class V20 extends Migration 'providerType' => MESSAGE_TYPE_EMAIL, 'identifier' => $document->getAttribute('email'), ]); - $this->projectDB->createDocument('targets', $target); + try { + $this->projectDB->createDocument('targets', $target); + } catch (Duplicate $th) { + Console::warning("Email target for user {$document->getId()} already exists."); + } } if ($document->getAttribute('phone', '') !== '') { @@ -519,7 +579,11 @@ class V20 extends Migration 'providerType' => MESSAGE_TYPE_SMS, 'identifier' => $document->getAttribute('phone'), ]); - $this->projectDB->createDocument('targets', $target); + try { + $this->projectDB->createDocument('targets', $target); + } catch (Duplicate $th) { + Console::warning("Email target for user {$document->getId()} already exists."); + } } break; case 'sessions': diff --git a/src/Appwrite/Network/Validator/Origin.php b/src/Appwrite/Network/Validator/Origin.php index 508961ab9e..fe10d87e59 100644 --- a/src/Appwrite/Network/Validator/Origin.php +++ b/src/Appwrite/Network/Validator/Origin.php @@ -2,8 +2,8 @@ namespace Appwrite\Network\Validator; -use Utopia\Validator\Hostname; use Utopia\Validator; +use Utopia\Validator\Hostname; class Origin extends Validator { diff --git a/src/Appwrite/Platform/Services/Tasks.php b/src/Appwrite/Platform/Services/Tasks.php index e50c7c1ddc..f1fd1945c4 100644 --- a/src/Appwrite/Platform/Services/Tasks.php +++ b/src/Appwrite/Platform/Services/Tasks.php @@ -15,11 +15,11 @@ use Appwrite\Platform\Tasks\Migrate; use Appwrite\Platform\Tasks\PatchRecreateRepositoriesDocuments; use Appwrite\Platform\Tasks\QueueCount; use Appwrite\Platform\Tasks\QueueRetry; -use Appwrite\Platform\Tasks\SDKs; -use Appwrite\Platform\Tasks\SSL; use Appwrite\Platform\Tasks\ScheduleFunctions; use Appwrite\Platform\Tasks\ScheduleMessages; +use Appwrite\Platform\Tasks\SDKs; use Appwrite\Platform\Tasks\Specs; +use Appwrite\Platform\Tasks\SSL; use Appwrite\Platform\Tasks\Upgrade; use Appwrite\Platform\Tasks\Vars; use Appwrite\Platform\Tasks\Version; diff --git a/src/Appwrite/Platform/Services/Workers.php b/src/Appwrite/Platform/Services/Workers.php index 84700e82e3..4adf9b76cb 100644 --- a/src/Appwrite/Platform/Services/Workers.php +++ b/src/Appwrite/Platform/Services/Workers.php @@ -2,20 +2,20 @@ namespace Appwrite\Platform\Services; -use Utopia\Platform\Service; use Appwrite\Platform\Workers\Audits; -use Appwrite\Platform\Workers\Webhooks; -use Appwrite\Platform\Workers\Mails; -use Appwrite\Platform\Workers\Messaging; +use Appwrite\Platform\Workers\Builds; use Appwrite\Platform\Workers\Certificates; use Appwrite\Platform\Workers\Databases; -use Appwrite\Platform\Workers\Functions; -use Appwrite\Platform\Workers\Builds; use Appwrite\Platform\Workers\Deletes; +use Appwrite\Platform\Workers\Functions; use Appwrite\Platform\Workers\Hamster; +use Appwrite\Platform\Workers\Mails; +use Appwrite\Platform\Workers\Messaging; +use Appwrite\Platform\Workers\Migrations; use Appwrite\Platform\Workers\Usage; use Appwrite\Platform\Workers\UsageDump; -use Appwrite\Platform\Workers\Migrations; +use Appwrite\Platform\Workers\Webhooks; +use Utopia\Platform\Service; class Workers extends Service { diff --git a/src/Appwrite/Platform/Tasks/CalcTierStats.php b/src/Appwrite/Platform/Tasks/CalcTierStats.php index 5723e256d5..fc01881523 100644 --- a/src/Appwrite/Platform/Tasks/CalcTierStats.php +++ b/src/Appwrite/Platform/Tasks/CalcTierStats.php @@ -2,17 +2,16 @@ namespace Appwrite\Platform\Tasks; -use League\Csv\CannotInsertRecord; +use League\Csv\Writer; +use PHPMailer\PHPMailer\PHPMailer; use Utopia\App; -use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; -use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Query; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; +use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Registry\Registry; use Utopia\Validator\Text; diff --git a/src/Appwrite/Platform/Tasks/CreateInfMetric.php b/src/Appwrite/Platform/Tasks/CreateInfMetric.php index cfb7486782..c50b6e09f9 100644 --- a/src/Appwrite/Platform/Tasks/CreateInfMetric.php +++ b/src/Appwrite/Platform/Tasks/CreateInfMetric.php @@ -2,13 +2,13 @@ namespace Appwrite\Platform\Tasks; +use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Exception; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Query; use Utopia\Platform\Action; -use Utopia\CLI\Console; -use Utopia\Database\Database; use Utopia\Validator\Text; class CreateInfMetric extends Action diff --git a/src/Appwrite/Platform/Tasks/DeleteOrphanedProjects.php b/src/Appwrite/Platform/Tasks/DeleteOrphanedProjects.php index 9b27176876..94879a4386 100644 --- a/src/Appwrite/Platform/Tasks/DeleteOrphanedProjects.php +++ b/src/Appwrite/Platform/Tasks/DeleteOrphanedProjects.php @@ -3,13 +3,13 @@ namespace Appwrite\Platform\Tasks; use Utopia\App; +use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Database\Database; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Platform\Action; -use Utopia\Cache\Cache; -use Utopia\CLI\Console; -use Utopia\Database\Database; use Utopia\Pools\Group; use Utopia\Registry\Registry; use Utopia\Validator\Boolean; diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php index 739a23aaf4..2886dcd4dd 100644 --- a/src/Appwrite/Platform/Tasks/Doctor.php +++ b/src/Appwrite/Platform/Tasks/Doctor.php @@ -2,16 +2,16 @@ namespace Appwrite\Platform\Tasks; +use Appwrite\ClamAV\Network; use Utopia\App; use Utopia\CLI\Console; -use Appwrite\ClamAV\Network; -use Utopia\Logger\Logger; -use Utopia\Storage\Device\Local; -use Utopia\Storage\Storage; use Utopia\Config\Config; use Utopia\Domains\Domain; +use Utopia\Logger\Logger; use Utopia\Platform\Action; use Utopia\Registry\Registry; +use Utopia\Storage\Device\Local; +use Utopia\Storage\Storage; class Doctor extends Action { @@ -200,10 +200,10 @@ class Doctor extends Action foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES ] as $key => $volume ) { $device = new Local($volume); @@ -228,10 +228,10 @@ class Doctor extends Action foreach ( [ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES + 'Uploads' => APP_STORAGE_UPLOADS, + 'Cache' => APP_STORAGE_CACHE, + 'Config' => APP_STORAGE_CONFIG, + 'Certs' => APP_STORAGE_CERTIFICATES ] as $key => $volume ) { $device = new Local($volume); diff --git a/src/Appwrite/Platform/Tasks/GetMigrationStats.php b/src/Appwrite/Platform/Tasks/GetMigrationStats.php index ed10ac345b..dd43f75447 100644 --- a/src/Appwrite/Platform/Tasks/GetMigrationStats.php +++ b/src/Appwrite/Platform/Tasks/GetMigrationStats.php @@ -3,14 +3,14 @@ namespace Appwrite\Platform\Tasks; use League\Csv\CannotInsertRecord; +use League\Csv\Writer; +use PHPMailer\PHPMailer\PHPMailer; use Utopia\App; -use Utopia\Platform\Action; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; +use Utopia\Platform\Action; use Utopia\Pools\Group; use Utopia\Registry\Registry; diff --git a/src/Appwrite/Platform/Tasks/Hamster.php b/src/Appwrite/Platform/Tasks/Hamster.php index 126ccd07df..7f8ef4041d 100644 --- a/src/Appwrite/Platform/Tasks/Hamster.php +++ b/src/Appwrite/Platform/Tasks/Hamster.php @@ -4,11 +4,11 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Event\Hamster as EventHamster; use Utopia\App; -use Utopia\Platform\Action; use Utopia\CLI\Console; use Utopia\Database\Database; -use Utopia\Database\Query; use Utopia\Database\Document; +use Utopia\Database\Query; +use Utopia\Platform\Action; class Hamster extends Action { diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index c6107c6ba8..4abd267684 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -8,9 +8,9 @@ use Appwrite\Docker\Env; use Appwrite\Utopia\View; use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Platform\Action; use Utopia\Validator\Boolean; use Utopia\Validator\Text; -use Utopia\Platform\Action; class Install extends Action { diff --git a/src/Appwrite/Platform/Tasks/Maintenance.php b/src/Appwrite/Platform/Tasks/Maintenance.php index 3245a92448..55bcd488a0 100644 --- a/src/Appwrite/Platform/Tasks/Maintenance.php +++ b/src/Appwrite/Platform/Tasks/Maintenance.php @@ -7,8 +7,8 @@ use Appwrite\Event\Delete; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database; -use Utopia\Database\Document; use Utopia\Database\DateTime; +use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Platform\Action; diff --git a/src/Appwrite/Platform/Tasks/Migrate.php b/src/Appwrite/Platform/Tasks/Migrate.php index 682b9b5559..6e4fe38eb7 100644 --- a/src/Appwrite/Platform/Tasks/Migrate.php +++ b/src/Appwrite/Platform/Tasks/Migrate.php @@ -2,15 +2,15 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; -use Utopia\CLI\Console; use Appwrite\Migration\Migration; use Utopia\App; use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Validator\Text; diff --git a/src/Appwrite/Platform/Tasks/PatchRecreateRepositoriesDocuments.php b/src/Appwrite/Platform/Tasks/PatchRecreateRepositoriesDocuments.php index 93e6c527bb..9cf65d05b6 100644 --- a/src/Appwrite/Platform/Tasks/PatchRecreateRepositoriesDocuments.php +++ b/src/Appwrite/Platform/Tasks/PatchRecreateRepositoriesDocuments.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; @@ -10,6 +9,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; use Utopia\Database\Query; +use Utopia\Platform\Action; use Utopia\Validator\Text; class PatchRecreateRepositoriesDocuments extends Action diff --git a/src/Appwrite/Platform/Tasks/QueueRetry.php b/src/Appwrite/Platform/Tasks/QueueRetry.php index 2781d9a3f7..465152f21d 100644 --- a/src/Appwrite/Platform/Tasks/QueueRetry.php +++ b/src/Appwrite/Platform/Tasks/QueueRetry.php @@ -7,7 +7,6 @@ use Utopia\CLI\Console; use Utopia\Platform\Action; use Utopia\Queue\Client; use Utopia\Queue\Connection; -use Utopia\Validator\Integer; use Utopia\Validator\WhiteList; use Utopia\Validator\Wildcard; diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index f20ce038bc..014e33109e 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -2,8 +2,8 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Appwrite\SDK\Language\Android; +use Appwrite\SDK\Language\Apple; use Appwrite\SDK\Language\CLI; use Appwrite\SDK\Language\Dart; use Appwrite\SDK\Language\Deno; @@ -18,12 +18,12 @@ use Appwrite\SDK\Language\Python; use Appwrite\SDK\Language\REST; use Appwrite\SDK\Language\Ruby; use Appwrite\SDK\Language\Swift; -use Appwrite\SDK\Language\Apple; use Appwrite\SDK\Language\Web; use Appwrite\SDK\SDK; use Appwrite\Spec\Swagger2; use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Platform\Action; class SDKs extends Action { diff --git a/src/Appwrite/Platform/Tasks/SSL.php b/src/Appwrite/Platform/Tasks/SSL.php index 12cb0d6be2..251d3a046b 100644 --- a/src/Appwrite/Platform/Tasks/SSL.php +++ b/src/Appwrite/Platform/Tasks/SSL.php @@ -2,11 +2,11 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; use Appwrite\Event\Certificate; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Document; +use Utopia\Platform\Action; use Utopia\Validator\Boolean; use Utopia\Validator\Hostname; diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index fbb2320a34..81110f5216 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -2,18 +2,16 @@ namespace Appwrite\Platform\Tasks; -use Cron\CronExpression; use Swoole\Timer; use Utopia\App; -use Utopia\Database\Exception; -use Utopia\Platform\Action; use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\Exception; use Utopia\Database\Query; -use Utopia\Database\Database; +use Utopia\Platform\Action; use Utopia\Pools\Group; -use Appwrite\Event\Func; use function Swoole\Coroutine\run; @@ -41,7 +39,7 @@ abstract class ScheduleBase extends Action ->inject('pools') ->inject('dbForConsole') ->inject('getProjectDB') - ->callback(fn(Group $pools, Database $dbForConsole, callable $getProjectDB) => $this->action($pools, $dbForConsole, $getProjectDB)); + ->callback(fn (Group $pools, Database $dbForConsole, callable $getProjectDB) => $this->action($pools, $dbForConsole, $getProjectDB)); } /** @@ -192,7 +190,7 @@ abstract class ScheduleBase extends Action Timer::tick( static::ENQUEUE_TIMER * 1000, - fn() => $this->enqueueResources($pools, $dbForConsole) + fn () => $this->enqueueResources($pools, $dbForConsole) ); $this->enqueueResources($pools, $dbForConsole); diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php index 05b094ac58..8e52973a0c 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php +++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php @@ -2,18 +2,9 @@ namespace Appwrite\Platform\Tasks; -use Appwrite\Event\Delete; -use Swoole\Timer; -use Utopia\Database\Document; -use Utopia\Platform\Action; -use Utopia\CLI\Console; -use Utopia\Database\DateTime; -use Utopia\Database\Query; +use Appwrite\Event\Messaging; use Utopia\Database\Database; use Utopia\Pools\Group; -use Appwrite\Event\Messaging; - -use function Swoole\Coroutine\run; class ScheduleMessages extends ScheduleBase { diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index d83312fad6..46c83fe2b1 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -2,8 +2,6 @@ namespace Appwrite\Platform\Tasks; -use Utopia\Platform\Action; -use Utopia\Validator\Text; use Appwrite\Specification\Format\OpenAPI3; use Appwrite\Specification\Format\Swagger2; use Appwrite\Specification\Specification; @@ -17,8 +15,10 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Adapter\MySQL; use Utopia\Database\Database; +use Utopia\Platform\Action; use Utopia\Registry\Registry; use Utopia\Request; +use Utopia\Validator\Text; use Utopia\Validator\WhiteList; class Specs extends Action diff --git a/src/Appwrite/Platform/Tasks/Vars.php b/src/Appwrite/Platform/Tasks/Vars.php index c97f77a9da..696073e568 100644 --- a/src/Appwrite/Platform/Tasks/Vars.php +++ b/src/Appwrite/Platform/Tasks/Vars.php @@ -3,8 +3,8 @@ namespace Appwrite\Platform\Tasks; use Utopia\App; -use Utopia\Config\Config; use Utopia\CLI\Console; +use Utopia\Config\Config; use Utopia\Platform\Action; class Vars extends Action diff --git a/src/Appwrite/Platform/Workers/Audits.php b/src/Appwrite/Platform/Workers/Audits.php index 53c16d8eb3..86ca59d3fd 100644 --- a/src/Appwrite/Platform/Workers/Audits.php +++ b/src/Appwrite/Platform/Workers/Audits.php @@ -71,11 +71,11 @@ class Audits extends Action ip: $ip, location: '', data: [ - 'userId' => $user->getId(), - 'userName' => $userName, - 'userEmail' => $userEmail, - 'mode' => $mode, - 'data' => $auditPayload, + 'userId' => $user->getId(), + 'userName' => $userName, + 'userEmail' => $userEmail, + 'mode' => $mode, + 'data' => $auditPayload, ] ); } diff --git a/src/Appwrite/Platform/Workers/Builds.php b/src/Appwrite/Platform/Workers/Builds.php index 5b2e5be761..b9f02a8f67 100644 --- a/src/Appwrite/Platform/Workers/Builds.php +++ b/src/Appwrite/Platform/Workers/Builds.php @@ -8,8 +8,8 @@ use Appwrite\Event\Usage; use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Utopia\Response\Model\Deployment; use Appwrite\Vcs\Comment; -use Swoole\Coroutine as Co; use Executor\Executor; +use Swoole\Coroutine as Co; use Utopia\App; use Utopia\Cache\Cache; use Utopia\CLI\Console; @@ -19,9 +19,9 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; -use Utopia\Database\Validator\Authorization; use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Authorization; use Utopia\Logger\Log; use Utopia\Platform\Action; use Utopia\Queue\Message; @@ -52,7 +52,7 @@ class Builds extends Action ->inject('dbForProject') ->inject('deviceForFunctions') ->inject('log') - ->callback(fn($message, Database $dbForConsole, Event $queueForEvents, Func $queueForFunctions, Usage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForEvents, $queueForFunctions, $usage, $cache, $dbForProject, $deviceForFunctions, $log)); + ->callback(fn ($message, Database $dbForConsole, Event $queueForEvents, Func $queueForFunctions, Usage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForEvents, $queueForFunctions, $usage, $cache, $dbForProject, $deviceForFunctions, $log)); } /** @@ -281,7 +281,7 @@ class Builds extends Action * Send realtime Event */ $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $build, project: $project @@ -357,7 +357,7 @@ class Builds extends Action /** Trigger Realtime */ $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $build, project: $project @@ -421,48 +421,48 @@ class Builds extends Action $err = $error; } }), - Co\go(function () use ($executor, $project, $deployment, &$response, &$build, $dbForProject, $allEvents, &$err) { - try { - $executor->getLogs( - deploymentId: $deployment->getId(), - projectId: $project->getId(), - callback: function ($logs) use (&$response, &$build, $dbForProject, $allEvents, $project) { - if ($response === null) { - $build = $dbForProject->getDocument('builds', $build->getId()); + Co\go(function () use ($executor, $project, $deployment, &$response, &$build, $dbForProject, $allEvents, &$err) { + try { + $executor->getLogs( + deploymentId: $deployment->getId(), + projectId: $project->getId(), + callback: function ($logs) use (&$response, &$build, $dbForProject, $allEvents, $project) { + if ($response === null) { + $build = $dbForProject->getDocument('builds', $build->getId()); - if ($build->isEmpty()) { - throw new Exception('Build not found', 404); - } + if ($build->isEmpty()) { + throw new Exception('Build not found', 404); + } - $build = $build->setAttribute('logs', $build->getAttribute('logs', '') . $logs); - $build = $dbForProject->updateDocument('builds', $build->getId(), $build); + $build = $build->setAttribute('logs', $build->getAttribute('logs', '') . $logs); + $build = $dbForProject->updateDocument('builds', $build->getId(), $build); - /** + /** * Send realtime Event */ - $target = Realtime::fromPayload( + $target = Realtime::fromPayload( // Pass first, most verbose event pattern - event: $allEvents[0], - payload: $build, - project: $project - ); - Realtime::send( - projectId: 'console', - payload: $build->getArrayCopy(), - events: $allEvents, - channels: $target['channels'], - roles: $target['roles'] - ); - } + event: $allEvents[0], + payload: $build, + project: $project + ); + Realtime::send( + projectId: 'console', + payload: $build->getArrayCopy(), + events: $allEvents, + channels: $target['channels'], + roles: $target['roles'] + ); } - ); - } catch (\Throwable $error) { - if (empty($err)) { - $err = $error; } + ); + } catch (\Throwable $error) { + if (empty($err)) { + $err = $error; } - }), - ]); + } + }), + ]); if ($err) { throw $err; @@ -502,7 +502,7 @@ class Builds extends Action ->setAttribute('resourceUpdatedAt', DateTime::now()) ->setAttribute('schedule', $function->getAttribute('schedule')) ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - Authorization::skip(fn() => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); + Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); } catch (\Throwable $th) { $endTime = DateTime::now(); $durationEnd = \microtime(true); @@ -521,7 +521,7 @@ class Builds extends Action * Send realtime Event */ $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $build, project: $project diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 13e85d473d..7cc32ca1c9 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -47,7 +47,7 @@ class Certificates extends Action ->inject('queueForEvents') ->inject('queueForFunctions') ->inject('log') - ->callback(fn(Message $message, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log)); + ->callback(fn (Message $message, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log)); } /** @@ -534,7 +534,7 @@ class Certificates extends Action 'ruleId' => $rule->getId(), ]); $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $rule, project: $project diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index ae8ed31621..a5ac3b47d1 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -9,11 +9,11 @@ use Utopia\Audit\Audit; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Exception as DatabaseException; use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; -use Utopia\Database\Exception as DatabaseException; use Utopia\Database\Query; use Utopia\Logger\Log; use Utopia\Platform\Action; @@ -37,7 +37,7 @@ class Databases extends Action ->inject('dbForConsole') ->inject('dbForProject') ->inject('log') - ->callback(fn(Message $message, Database $dbForConsole, Database $dbForProject, Log $log) => $this->action($message, $dbForConsole, $dbForProject, $log)); + ->callback(fn (Message $message, Database $dbForConsole, Database $dbForProject, Log $log) => $this->action($message, $dbForConsole, $dbForProject, $log)); } /** @@ -613,7 +613,7 @@ class Databases extends Action array $events ): void { $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $events[0], payload: $attribute, project: $project, diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 51b2475171..fdf494afec 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -8,19 +8,19 @@ use Executor\Executor; use Throwable; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; +use Utopia\App; use Utopia\Audit\Audit; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; -use Utopia\Database\Database; -use Utopia\App; use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\Exception as DatabaseException; use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; -use Utopia\Database\Exception as DatabaseException; use Utopia\Database\Query; use Utopia\Logger\Log; use Utopia\Platform\Action; @@ -71,6 +71,7 @@ class Deletes extends Action $datetime = $payload['datetime'] ?? null; $hourlyUsageRetentionDatetime = $payload['hourlyUsageRetentionDatetime'] ?? null; $resource = $payload['resource'] ?? null; + $resourceType = $payload['resourceType'] ?? null; $document = new Document($payload['document'] ?? []); $project = new Document($payload['project'] ?? []); @@ -80,12 +81,6 @@ class Deletes extends Action switch (\strval($type)) { case DELETE_TYPE_DOCUMENT: switch ($document->getCollection()) { - case DELETE_TYPE_DATABASES: - $this->deleteDatabase($getProjectDB, $document, $project); - break; - case DELETE_TYPE_COLLECTIONS: - $this->deleteCollection($getProjectDB, $document, $project); - break; case DELETE_TYPE_PROJECTS: $this->deleteProject($dbForConsole, $getProjectDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $document); break; @@ -114,10 +109,6 @@ class Deletes extends Action $this->deleteRule($dbForConsole, $document); break; default: - if (\str_starts_with($document->getCollection(), 'database_')) { - $this->deleteCollection($getProjectDB, $document, $project); - break; - } Console::error('No lazy delete operation available for document of type: ' . $document->getCollection()); break; } @@ -147,7 +138,7 @@ class Deletes extends Action $this->deleteUsageStats($project, $getProjectDB, $hourlyUsageRetentionDatetime); break; case DELETE_TYPE_CACHE_BY_RESOURCE: - $this->deleteCacheByResource($project, $getProjectDB, $resource); + $this->deleteCacheByResource($project, $getProjectDB, $resource, $resourceType); break; case DELETE_TYPE_CACHE_BY_TIMESTAMP: $this->deleteCacheByDate($project, $getProjectDB, $datetime); @@ -332,32 +323,37 @@ class Deletes extends Action * @param string $resource * @return void * @throws Authorization + * @param string|null $resourceType + * @throws Exception */ - private function deleteCacheByResource(Document $project, callable $getProjectDB, string $resource): void + private function deleteCacheByResource(Document $project, callable $getProjectDB, string $resource, string $resourceType = null): void { $projectId = $project->getId(); $dbForProject = $getProjectDB($project); - $document = $dbForProject->findOne('cache', [Query::equal('resource', [$resource])]); - if ($document) { - $cache = new Cache( - new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId) - ); + $cache = new Cache( + new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId) + ); - $this->deleteById( - $document, - $dbForProject, - function ($document) use ($cache, $projectId) { - $path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId(); - - if ($cache->purge($document->getId())) { - Console::success('Deleting cache file: ' . $path); - } else { - Console::error('Failed to delete cache file: ' . $path); - } - } - ); + $query[] = Query::equal('resource', [$resource]); + if (!empty($resourceType)) { + $query[] = Query::equal('resourceType', [$resourceType]); } + + $this->deleteByGroup( + 'cache', + $query, + $dbForProject, + function (Document $document) use ($cache, $projectId) { + $path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId(); + + if ($cache->purge($document->getId())) { + Console::success('Deleting cache file: ' . $path); + } else { + Console::error('Failed to delete cache file: ' . $path); + } + } + ); } /** @@ -397,72 +393,6 @@ class Deletes extends Action ); } - /** - * @param callable $getProjectDB - * @param Document $document - * @param Document $project - * @return void - * @throws Exception - */ - private function deleteDatabase(callable $getProjectDB, Document $document, Document $project): void - { - $databaseId = $document->getId(); - $dbForProject = $getProjectDB($project); - - $this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($getProjectDB, $project) { - $this->deleteCollection($getProjectDB, $document, $project); - }); - - $dbForProject->deleteCollection('database_' . $document->getInternalId()); - $this->deleteAuditLogsByResource($getProjectDB, 'database/' . $databaseId, $project); - } - - /** - * @param callable $getProjectDB - * @param Document $document teams document - * @param Document $project - * @return void - * @throws Exception - */ - private function deleteCollection(callable $getProjectDB, Document $document, Document $project): void - { - $collectionId = $document->getId(); - $collectionInternalId = $document->getInternalId(); - $databaseId = $document->getAttribute('databaseId'); - $databaseInternalId = $document->getAttribute('databaseInternalId'); - - $dbForProject = $getProjectDB($project); - - $relationships = \array_filter( - $document->getAttribute('attributes'), - fn ($attribute) => $attribute['type'] === Database::VAR_RELATIONSHIP - ); - - foreach ($relationships as $relationship) { - if (!$relationship['twoWay']) { - continue; - } - $relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']); - $dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']); - $dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId()); - $dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId()); - } - - $dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId()); - - $this->deleteByGroup('attributes', [ - Query::equal('databaseInternalId', [$databaseInternalId]), - Query::equal('collectionInternalId', [$collectionInternalId]) - ], $dbForProject); - - $this->deleteByGroup('indexes', [ - Query::equal('databaseInternalId', [$databaseInternalId]), - Query::equal('collectionInternalId', [$collectionInternalId]) - ], $dbForProject); - - $this->deleteAuditLogsByResource($getProjectDB, 'database/' . $databaseId . '/collection/' . $collectionId, $project); - } - /** * @param Database $dbForConsole * @param callable $getProjectDB diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index f0a71f2bd4..05695d9e26 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -46,7 +46,7 @@ class Functions extends Action ->inject('queueForEvents') ->inject('queueForUsage') ->inject('log') - ->callback(fn(Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log) => $this->action($message, $dbForProject, $queueForFunctions, $queueForEvents, $queueForUsage, $log)); + ->callback(fn (Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log) => $this->action($message, $dbForProject, $queueForFunctions, $queueForEvents, $queueForUsage, $log)); } /** @@ -467,7 +467,7 @@ class Functions extends Action 'executionId' => $execution->getId() ]); $target = Realtime::fromPayload( - // Pass first, most verbose event pattern + // Pass first, most verbose event pattern event: $allEvents[0], payload: $execution ); diff --git a/src/Appwrite/Platform/Workers/Hamster.php b/src/Appwrite/Platform/Workers/Hamster.php index 1069ff96fa..b72b7f7030 100644 --- a/src/Appwrite/Platform/Workers/Hamster.php +++ b/src/Appwrite/Platform/Workers/Hamster.php @@ -10,14 +10,13 @@ use Utopia\App; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\Platform\Action; use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use Utopia\Database\Document; -use Utopia\Queue\Message; -use Utopia\Logger\Log; +use Utopia\Platform\Action; use Utopia\Pools\Group; +use Utopia\Queue\Message; class Hamster extends Action { diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 3fbe30ccca..0f1503b3e5 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -3,24 +3,23 @@ namespace Appwrite\Platform\Workers; use Appwrite\Event\Usage; -use Appwrite\Extend\Exception; use Appwrite\Messaging\Status as MessageStatus; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; -use Utopia\DSN\DSN; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; +use Utopia\DSN\DSN; use Utopia\Logger\Log; use Utopia\Messaging\Adapter\Email as EmailAdapter; use Utopia\Messaging\Adapter\Email\Mailgun; -use Utopia\Messaging\Adapter\Email\SMTP; use Utopia\Messaging\Adapter\Email\Sendgrid; -use Utopia\Messaging\Adapter\Push as PushAdapter; +use Utopia\Messaging\Adapter\Email\SMTP; use Utopia\Messaging\Adapter\Push\APNS; +use Utopia\Messaging\Adapter\Push as PushAdapter; use Utopia\Messaging\Adapter\Push\FCM; use Utopia\Messaging\Adapter\SMS as SMSAdapter; use Utopia\Messaging\Adapter\SMS\Mock; @@ -60,7 +59,7 @@ class Messaging extends Action ->inject('deviceForFiles') ->inject('deviceForLocalFiles') ->inject('queueForUsage') - ->callback(fn(Message $message, Log $log, Database $dbForProject, Device $deviceForFiles, Device $deviceForLocalFiles, Usage $queueForUsage) => $this->action($message, $log, $dbForProject, $deviceForFiles, $deviceForLocalFiles, $queueForUsage)); + ->callback(fn (Message $message, Log $log, Database $dbForProject, Device $deviceForFiles, Device $deviceForLocalFiles, Usage $queueForUsage) => $this->action($message, $log, $dbForProject, $deviceForFiles, $deviceForLocalFiles, $queueForUsage)); } /** @@ -100,7 +99,7 @@ class Messaging extends Action case MESSAGE_SEND_TYPE_EXTERNAL: $message = $dbForProject->getDocument('messages', $payload['messageId']); - $this->sendExternalMessage($dbForProject, $message, $deviceForFiles, $deviceForLocalFiles,); + $this->sendExternalMessage($dbForProject, $message, $deviceForFiles, $deviceForLocalFiles, ); break; default: throw new \Exception('Unknown message type: ' . $type); @@ -628,7 +627,7 @@ class Messaging extends Action $body = $message['data']['body']; $data = $message['data']['data'] ?? null; $action = $message['data']['action'] ?? null; - $image = $message['data']['image'] ?? null; + $image = $message['data']['image']['url'] ?? null; $sound = $message['data']['sound'] ?? null; $icon = $message['data']['icon'] ?? null; $color = $message['data']['color'] ?? null; diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index f73eee7f36..7bbfcfbce2 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -2,30 +2,30 @@ namespace Appwrite\Platform\Workers; +use Appwrite\Event\Event; +use Appwrite\Messaging\Adapter\Realtime; +use Appwrite\Permission; +use Appwrite\Role; use Exception; +use Utopia\CLI\Console; +use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization; use Utopia\Database\Exception\Conflict; use Utopia\Database\Exception\Restricted; use Utopia\Database\Exception\Structure; -use Utopia\Platform\Action; -use Utopia\Queue\Message; -use Appwrite\Event\Event; -use Appwrite\Messaging\Adapter\Realtime; -use Appwrite\Permission; -use Appwrite\Role; -use Utopia\CLI\Console; -use Utopia\Database\Database; use Utopia\Database\Helpers\ID; use Utopia\Logger\Log; use Utopia\Migration\Destinations\Appwrite as DestinationsAppwrite; +use Utopia\Migration\Exception as MigrationException; use Utopia\Migration\Source; use Utopia\Migration\Sources\Appwrite; use Utopia\Migration\Sources\Firebase; use Utopia\Migration\Sources\NHost; use Utopia\Migration\Sources\Supabase; use Utopia\Migration\Transfer; -use Utopia\Migration\Exception as MigrationException; +use Utopia\Platform\Action; +use Utopia\Queue\Message; class Migrations extends Action { @@ -48,7 +48,7 @@ class Migrations extends Action ->inject('dbForProject') ->inject('dbForConsole') ->inject('log') - ->callback(fn(Message $message, Database $dbForProject, Database $dbForConsole, Log $log) => $this->action($message, $dbForProject, $dbForConsole, $log)); + ->callback(fn (Message $message, Database $dbForProject, Database $dbForConsole, Log $log) => $this->action($message, $dbForProject, $dbForConsole, $log)); } /** diff --git a/src/Appwrite/Platform/Workers/Usage.php b/src/Appwrite/Platform/Workers/Usage.php index c84f57e0f2..3227153e08 100644 --- a/src/Appwrite/Platform/Workers/Usage.php +++ b/src/Appwrite/Platform/Workers/Usage.php @@ -2,8 +2,8 @@ namespace Appwrite\Platform\Workers; -use Exception; use Appwrite\Event\UsageDump; +use Exception; use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\DateTime; @@ -36,7 +36,7 @@ class Usage extends Action ->inject('getProjectDB') ->inject('queueForUsageDump') ->callback(function (Message $message, callable $getProjectDB, UsageDump $queueForUsageDump) { - $this->action($message, $getProjectDB, $queueForUsageDump); + $this->action($message, $getProjectDB, $queueForUsageDump); }); $this->lastTriggeredTime = time(); @@ -77,7 +77,7 @@ class Usage extends Action $this->stats[$projectId]['project'] = $project; $this->stats[$projectId]['receivedAt'] = DateTime::now(); foreach ($payload['metrics'] ?? [] as $metric) { - $this->keys++; + $this->keys++; if (!isset($this->stats[$projectId]['keys'][$metric['key']])) { $this->stats[$projectId]['keys'][$metric['key']] = $metric['value']; continue; @@ -103,15 +103,15 @@ class Usage extends Action } } - /** - * On Documents that tied by relations like functions>deployments>build || documents>collection>database || buckets>files. - * When we remove a parent document we need to deduct his children aggregation from the project scope. - * @param Document $project - * @param Document $document - * @param array $metrics - * @param callable $getProjectDB - * @return void - */ + /** + * On Documents that tied by relations like functions>deployments>build || documents>collection>database || buckets>files. + * When we remove a parent document we need to deduct his children aggregation from the project scope. + * @param Document $project + * @param Document $document + * @param array $metrics + * @param callable $getProjectDB + * @return void + */ private function reduce(Document $project, Document $document, array &$metrics, callable $getProjectDB): void { $dbForProject = $getProjectDB($project); @@ -122,8 +122,8 @@ class Usage extends Action $sessions = count($document->getAttribute(METRIC_SESSIONS, 0)); if (!empty($sessions)) { $metrics[] = [ - 'key' => METRIC_SESSIONS, - 'value' => ($sessions * -1), + 'key' => METRIC_SESSIONS, + 'value' => ($sessions * -1), ]; } break; @@ -132,15 +132,15 @@ class Usage extends Action $documents = $dbForProject->getDocument('stats', md5(self::INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS))); if (!empty($collections['value'])) { $metrics[] = [ - 'key' => METRIC_COLLECTIONS, - 'value' => ($collections['value'] * -1), + 'key' => METRIC_COLLECTIONS, + 'value' => ($collections['value'] * -1), ]; } if (!empty($documents['value'])) { $metrics[] = [ - 'key' => METRIC_DOCUMENTS, - 'value' => ($documents['value'] * -1), + 'key' => METRIC_DOCUMENTS, + 'value' => ($documents['value'] * -1), ]; } break; @@ -151,12 +151,12 @@ class Usage extends Action if (!empty($documents['value'])) { $metrics[] = [ - 'key' => METRIC_DOCUMENTS, - 'value' => ($documents['value'] * -1), + 'key' => METRIC_DOCUMENTS, + 'value' => ($documents['value'] * -1), ]; $metrics[] = [ - 'key' => str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_DOCUMENTS), - 'value' => ($documents['value'] * -1), + 'key' => str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_DOCUMENTS), + 'value' => ($documents['value'] * -1), ]; } break; @@ -167,15 +167,15 @@ class Usage extends Action if (!empty($files['value'])) { $metrics[] = [ - 'key' => METRIC_FILES, - 'value' => ($files['value'] * -1), + 'key' => METRIC_FILES, + 'value' => ($files['value'] * -1), ]; } if (!empty($storage['value'])) { $metrics[] = [ - 'key' => METRIC_FILES_STORAGE, - 'value' => ($storage['value'] * -1), + 'key' => METRIC_FILES_STORAGE, + 'value' => ($storage['value'] * -1), ]; } break; @@ -191,50 +191,50 @@ class Usage extends Action if (!empty($deployments['value'])) { $metrics[] = [ - 'key' => METRIC_DEPLOYMENTS, - 'value' => ($deployments['value'] * -1), + 'key' => METRIC_DEPLOYMENTS, + 'value' => ($deployments['value'] * -1), ]; } if (!empty($deploymentsStorage['value'])) { $metrics[] = [ - 'key' => METRIC_DEPLOYMENTS_STORAGE, - 'value' => ($deploymentsStorage['value'] * -1), + 'key' => METRIC_DEPLOYMENTS_STORAGE, + 'value' => ($deploymentsStorage['value'] * -1), ]; } if (!empty($builds['value'])) { $metrics[] = [ - 'key' => METRIC_BUILDS, - 'value' => ($builds['value'] * -1), + 'key' => METRIC_BUILDS, + 'value' => ($builds['value'] * -1), ]; } if (!empty($buildsStorage['value'])) { $metrics[] = [ - 'key' => METRIC_BUILDS_STORAGE, - 'value' => ($buildsStorage['value'] * -1), + 'key' => METRIC_BUILDS_STORAGE, + 'value' => ($buildsStorage['value'] * -1), ]; } if (!empty($buildsCompute['value'])) { $metrics[] = [ - 'key' => METRIC_BUILDS_COMPUTE, - 'value' => ($buildsCompute['value'] * -1), + 'key' => METRIC_BUILDS_COMPUTE, + 'value' => ($buildsCompute['value'] * -1), ]; } if (!empty($executions['value'])) { $metrics[] = [ - 'key' => METRIC_EXECUTIONS, - 'value' => ($executions['value'] * -1), + 'key' => METRIC_EXECUTIONS, + 'value' => ($executions['value'] * -1), ]; } if (!empty($executionsCompute['value'])) { $metrics[] = [ - 'key' => METRIC_EXECUTIONS_COMPUTE, - 'value' => ($executionsCompute['value'] * -1), + 'key' => METRIC_EXECUTIONS_COMPUTE, + 'value' => ($executionsCompute['value'] * -1), ]; } break; diff --git a/src/Appwrite/Platform/Workers/UsageDump.php b/src/Appwrite/Platform/Workers/UsageDump.php index da8995b631..e1e62feb9f 100644 --- a/src/Appwrite/Platform/Workers/UsageDump.php +++ b/src/Appwrite/Platform/Workers/UsageDump.php @@ -4,11 +4,11 @@ namespace Appwrite\Platform\Workers; use Appwrite\Extend\Exception; use Utopia\App; +use Utopia\CLI\Console; +use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate; use Utopia\Platform\Action; -use Utopia\CLI\Console; -use Utopia\Database\DateTime; use Utopia\Queue\Message; class UsageDump extends Action diff --git a/src/Appwrite/Platform/Workers/Webhooks.php b/src/Appwrite/Platform/Workers/Webhooks.php index 979e0be381..da5a82999f 100644 --- a/src/Appwrite/Platform/Workers/Webhooks.php +++ b/src/Appwrite/Platform/Workers/Webhooks.php @@ -6,8 +6,8 @@ use Appwrite\Event\Mail; use Appwrite\Template\Template; use Exception; use Utopia\App; -use Utopia\Database\Document; use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Logger\Log; use Utopia\Platform\Action; diff --git a/src/Appwrite/Specification/Format.php b/src/Appwrite/Specification/Format.php index b0fcb3f540..30ce6470e1 100644 --- a/src/Appwrite/Specification/Format.php +++ b/src/Appwrite/Specification/Format.php @@ -2,10 +2,10 @@ namespace Appwrite\Specification; +use Appwrite\Utopia\Response\Model; use Utopia\App; use Utopia\Config\Config; use Utopia\Route; -use Appwrite\Utopia\Response\Model; abstract class Format { diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 09c4b2ebc9..a2539f30b9 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -291,7 +291,7 @@ class OpenAPI3 extends Format case 'Utopia\Database\Validator\UID': case 'Utopia\Validator\Text': $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['schema']['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>'; break; case 'Utopia\Validator\Boolean': $node['schema']['type'] = $validator->getType(); @@ -302,7 +302,7 @@ class OpenAPI3 extends Format $node['schema']['x-upload-id'] = true; } $node['schema']['type'] = $validator->getType(); - $node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['schema']['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>'; break; case 'Utopia\Database\Validator\DatetimeValidator': $node['schema']['type'] = $validator->getType(); @@ -432,9 +432,9 @@ class OpenAPI3 extends Format } if ($allowed) { - $node['schema']['enum'] = $validator->getList(); - $node['schema']['x-enum-name'] = $this->getEnumName($route->getLabel('sdk.namespace', ''), $method, $name); - $node['schema']['x-enum-keys'] = $this->getEnumKeys($route->getLabel('sdk.namespace', ''), $method, $name); + $node['schema']['enum'] = $validator->getList(); + $node['schema']['x-enum-name'] = $this->getEnumName($route->getLabel('sdk.namespace', ''), $method, $name); + $node['schema']['x-enum-keys'] = $this->getEnumKeys($route->getLabel('sdk.namespace', ''), $method, $name); } if ($validator->getType() === 'integer') { $node['format'] = 'int32'; diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index f923741b45..dd2b12b6b6 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -290,7 +290,7 @@ class Swagger2 extends Format case 'Utopia\Validator\Text': case 'Utopia\Database\Validator\UID': $node['type'] = $validator->getType(); - $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>'; break; case 'Utopia\Validator\Boolean': $node['type'] = $validator->getType(); @@ -301,7 +301,7 @@ class Swagger2 extends Format $node['x-upload-id'] = true; } $node['type'] = $validator->getType(); - $node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']'; + $node['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>'; break; case 'Utopia\Database\Validator\DatetimeValidator': $node['type'] = $validator->getType(); diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php index 1463316ad1..4a35c82b73 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php @@ -2,8 +2,6 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Select; - class Attributes extends Base { public const ALLOWED_ATTRIBUTES = [ diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php index d06111f60c..a3555c08dd 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Base.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Base.php @@ -2,16 +2,15 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Appwrite\Extend\Exception; -use Utopia\Database\Validator\Queries; -use Utopia\Database\Validator\Query\Limit; -use Utopia\Database\Validator\Query\Offset; -use Utopia\Database\Validator\Query\Cursor; -use Utopia\Database\Validator\Query\Filter; -use Utopia\Database\Validator\Query\Order; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Queries; +use Utopia\Database\Validator\Query\Cursor; +use Utopia\Database\Validator\Query\Filter; +use Utopia\Database\Validator\Query\Limit; +use Utopia\Database\Validator\Query\Offset; +use Utopia\Database\Validator\Query\Order; class Base extends Queries { diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php b/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php index 7fff26db7f..5a0befb739 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Projects.php @@ -2,8 +2,6 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Appwrite\Utopia\Database\Validator\Queries\Base; - class Projects extends Base { public const ALLOWED_ATTRIBUTES = [ diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php b/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php index 52c7abca1d..5d7a5e5cee 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Variables.php @@ -2,8 +2,6 @@ namespace Appwrite\Utopia\Database\Validator\Queries; -use Appwrite\Utopia\Database\Validator\Queries\Base; - class Variables extends Base { public const ALLOWED_ATTRIBUTES = [ diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 9ad2f6cb7b..3f0a196d5e 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -9,7 +9,10 @@ use Utopia\Swoole\Request as UtopiaRequest; class Request extends UtopiaRequest { - private static ?Filter $filter = null; + /** + * @var array + */ + private array $filters = []; private static ?Route $route = null; public function __construct(SwooleRequest $request) @@ -24,35 +27,48 @@ class Request extends UtopiaRequest { $parameters = parent::getParams(); - if (self::hasFilter() && self::hasRoute()) { + if ($this->hasFilters() && self::hasRoute()) { $method = self::getRoute()->getLabel('sdk.method', 'unknown'); $endpointIdentifier = self::getRoute()->getLabel('sdk.namespace', 'unknown') . '.' . $method; - $parameters = self::getFilter()->parse($parameters, $endpointIdentifier); + + foreach ($this->getFilters() as $filter) { + $parameters = $filter->parse($parameters, $endpointIdentifier); + } } return $parameters; } /** - * Function to set a response filter + * Function to add a response filter, the order of filters are first in - first out. * - * @param Filter|null $filter Filter the response filter to set + * @param Filter $filter the response filter to set * * @return void */ - public static function setFilter(?Filter $filter): void + public function addFilter(Filter $filter): void { - self::$filter = $filter; + $this->filters[] = $filter; } /** * Return the currently set filter * - * @return Filter|null + * @return array */ - public static function getFilter(): ?Filter + public function getFilters(): array { - return self::$filter; + return $this->filters; + } + + /** + * Reset filters + * + * @return void + */ + public function resetFilters(): void + { + $this->filters = []; } /** @@ -60,9 +76,9 @@ class Request extends UtopiaRequest * * @return bool */ - public static function hasFilter(): bool + public function hasFilters(): bool { - return self::$filter != null; + return !empty($this->filters); } /** @@ -94,7 +110,7 @@ class Request extends UtopiaRequest */ public static function hasRoute(): bool { - return self::$route != null; + return self::$route !== null; } /** diff --git a/src/Appwrite/Utopia/Request/Filters/V12.php b/src/Appwrite/Utopia/Request/Filters/V12.php deleted file mode 100644 index f2a65307ae..0000000000 --- a/src/Appwrite/Utopia/Request/Filters/V12.php +++ /dev/null @@ -1,171 +0,0 @@ - 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); - - if ($filterValue === 'true' || $filterValue === 'false') { - // Let's keep it at true and false string, but without "" around - // No action needed - } else { - $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']); - $content['queries'] = $queries; - - return $content; - } -} diff --git a/src/Appwrite/Utopia/Request/Filters/V13.php b/src/Appwrite/Utopia/Request/Filters/V13.php deleted file mode 100644 index e1122fdd71..0000000000 --- a/src/Appwrite/Utopia/Request/Filters/V13.php +++ /dev/null @@ -1,38 +0,0 @@ -convertStringToNum($content, "min"); - $content = $this->convertStringToNum($content, "max"); - $content = $this->convertStringToNum($content, "default"); - break; - case "functions.createExecution": - $content = $this->convertExecution($content); - } - - return $content; - } - - private function convertStringToNum($content, $value) - { - $content[$value] = is_null($content[$value]) ? null : (int)$content[$value]; - return $content; - } - - private function convertExecution($content) - { - $content['async'] = true; - return $content; - } -} diff --git a/src/Appwrite/Utopia/Request/Filters/V14.php b/src/Appwrite/Utopia/Request/Filters/V14.php deleted file mode 100644 index 7130307f0d..0000000000 --- a/src/Appwrite/Utopia/Request/Filters/V14.php +++ /dev/null @@ -1,34 +0,0 @@ -convertEvents($content); - break; - } - - return $content; - } - - private function convertEvents($content) - { - $migration = new MigrationV13(); - - $events = $content['events'] ?? []; - $content['events'] = $migration->migrateEvents($events); - - return $content; - } -} diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php deleted file mode 100644 index 318096fe0d..0000000000 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ /dev/null @@ -1,275 +0,0 @@ -convertLimitAndOffset($content); - break; - case 'account.initials': - unset($content['color']); - break; - case 'databases.list': - case 'databases.listCollections': - case 'functions.list': - case 'functions.listDeployments': - case 'projects.list': - case 'storage.listBuckets': - case 'storage.listFiles': - case 'teams.list': - case 'teams.listMemberships': - case 'users.list': - $content = $this->convertLimitAndOffset($content); - $content = $this->convertCursor($content); - $content = $this->convertOrderType($content); - break; - case 'databases.createCollection': - case 'databases.updateCollection': - $content = $this->convertCollectionPermission($content); - $content = $this->convertReadWrite($content); - break; - case 'databases.createDocument': - case 'databases.updateDocument': - case 'storage.createFile': - case 'storage.updateFile': - $content = $this->convertReadWrite($content); - break; - case 'databases.listDocuments': - $content = $this->convertFilters($content); - $content = $this->convertLimitAndOffset($content); - $content = $this->convertCursor($content); - $content = $this->convertOrders($content); - break; - case 'functions.create': - case 'functions.update': - $content = $this->convertExecute($content); - break; - case 'functions.listExecutions': - $content = $this->convertLimitAndOffset($content); - $content = $this->convertCursor($content); - break; - case 'projects.createKey': - case 'projects.updateKey': - $content = $this->convertExpire($content); - break; - case 'storage.createBucket': - case 'storage.updateBucket': - $content = $this->convertBucketPermission($content); - $content = $this->convertReadWrite($content); - break; - } - - return $content; - } - - protected function convertLimitAndOffset($content) - { - if (isset($content['limit'])) { - $content['queries'][] = 'limit(' . $content['limit'] . ')'; - } - - if (isset($content['offset'])) { - $content['queries'][] = 'offset(' . $content['offset'] . ')'; - } - - unset($content['limit']); - unset($content['offset']); - - return $content; - } - - protected function convertCursor($content) - { - if (isset($content['cursor'])) { - $cursorDirection = $content['cursorDirection'] ?? Database::CURSOR_AFTER; - - if ($cursorDirection === Database::CURSOR_BEFORE) { - $content['queries'][] = 'cursorBefore("' . $content["cursor"] . '")'; - } else { - $content['queries'][] = 'cursorAfter("' . $content["cursor"] . '")'; - } - } - - unset($content['cursor']); - unset($content['cursorDirection']); - - return $content; - } - - protected function convertOrderType($content) - { - if (isset($content['orderType'])) { - if ($content['orderType'] === Database::ORDER_DESC) { - $content['queries'][] = 'orderDesc("")'; - } else { - $content['queries'][] = 'orderAsc("")'; - } - } - unset($content['orderType']); - - return $content; - } - - protected function convertOrders($content) - { - if (isset($content['orderTypes'])) { - foreach ($content['orderTypes'] as $i => $type) { - $attribute = $content['orderAttributes'][$i] ?? ''; - - if ($type === Database::ORDER_DESC) { - $content['queries'][] = 'orderDesc("' . $attribute . '")'; - } else { - $content['queries'][] = 'orderAsc("' . $attribute . '")'; - } - } - } - - unset($content['orderAttributes']); - unset($content['orderTypes']); - - return $content; - } - - protected function convertCollectionPermission($content) - { - if (isset($content['permission'])) { - $content['documentSecurity'] = $content['permission'] === 'document'; - } - - unset($content['permission']); - - return $content; - } - - protected function convertReadWrite($content) - { - if (isset($content['read'])) { - foreach ($content['read'] as $read) { - if ($read === 'role:all') { - $content['permissions'][] = Permission::read(Role::any()); - } elseif ($read === 'role:guest') { - $content['permissions'][] = Permission::read(Role::guests()); - } elseif ($read === 'role:member') { - $content['permissions'][] = Permission::read(Role::users()); - } elseif (str_contains($read, ':')) { - $content['permissions'][] = Permission::read(Role::parse($read)); - } - } - } - - if (isset($content['write'])) { - foreach ($content['write'] as $write) { - if ($write === 'role:all' || $write === 'role:member') { - $content['permissions'][] = Permission::write(Role::users()); - } elseif ($write === 'role:guest') { - // don't add because, historically, - // role:guest for write did nothing - } elseif (str_contains($write, ':')) { - $content['permissions'][] = Permission::write(Role::parse($write)); - } - } - } - - unset($content['read']); - unset($content['write']); - - return $content; - } - - protected function convertFilters($content) - { - if (!isset($content['queries'])) { - return $content; - } - - $operations = [ - 'equal' => Query::TYPE_EQUAL, - 'notEqual' => Query::TYPE_NOT_EQUAL, - 'lesser' => Query::TYPE_LESSER, - 'lesserEqual' => Query::TYPE_LESSER_EQUAL, - 'greater' => Query::TYPE_GREATER, - 'greaterEqual' => Query::TYPE_GREATER_EQUAL, - 'search' => Query::TYPE_SEARCH, - ]; - foreach ($content['queries'] as $i => $query) { - foreach ($operations as $oldOperation => $newOperation) { - $middle = ".$oldOperation("; - if (str_contains($query, $middle)) { - $parts = explode($middle, $query); - if (count($parts) > 1) { - $attribute = $parts[0]; - $value = rtrim($parts[1], ")"); - $content['queries'][$i] = $newOperation . '("' . $attribute . '", [' . $value . '])'; - } - } - } - } - return $content; - } - - protected function convertExecute($content) - { - if (!isset($content['execute'])) { - return $content; - } - - $execute = []; - foreach ($content['execute'] as $role) { - if ($role === 'role:all' || $role === 'role:member') { - $execute[] = Role::users()->toString(); - } elseif ($role === 'role:guest') { - // don't add because, historically, - // role:guest for write did nothing - } elseif (str_contains($role, ':')) { - $execute[] = $role; - } - } - $content['execute'] = $execute; - - return $content; - } - - protected function convertExpire($content) - { - if (!isset($content['expire'])) { - return $content; - } - - $expire = (int) $content['expire']; - - if ($expire === 0) { - $content['expire'] = null; - } else { - $content['expire'] = date(\DateTime::RFC3339_EXTENDED, $expire); - } - - return $content; - } - - protected function convertBucketPermission($content) - { - if (isset($content['permission'])) { - $content['fileSecurity'] = $content['permission'] === 'file'; - } - - unset($content['permission']); - - return $content; - } -} diff --git a/src/Appwrite/Utopia/Request/Filters/V17.php b/src/Appwrite/Utopia/Request/Filters/V17.php index d7a4039d7e..83ec62a168 100644 --- a/src/Appwrite/Utopia/Request/Filters/V17.php +++ b/src/Appwrite/Utopia/Request/Filters/V17.php @@ -24,7 +24,7 @@ class V17 extends Filter case 'account.updateRecovery': unset($content['passwordAgain']); break; - // Queries + // Queries case 'account.listIdentities': case 'account.listLogs': case 'databases.list': diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 77e86212f1..6601a36075 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -2,10 +2,6 @@ namespace Appwrite\Utopia; -use Exception; -use Utopia\Swoole\Response as SwooleResponse; -use Swoole\Http\Response as SwooleHTTPResponse; -use Utopia\Database\Document; use Appwrite\Utopia\Response\Filter; use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response\Model\Account; @@ -16,80 +12,83 @@ use Appwrite\Utopia\Response\Model\AlgoPhpass; use Appwrite\Utopia\Response\Model\AlgoScrypt; use Appwrite\Utopia\Response\Model\AlgoScryptModified; use Appwrite\Utopia\Response\Model\AlgoSha; -use Appwrite\Utopia\Response\Model\None; use Appwrite\Utopia\Response\Model\Any; use Appwrite\Utopia\Response\Model\Attribute; -use Appwrite\Utopia\Response\Model\AttributeList; -use Appwrite\Utopia\Response\Model\AttributeString; -use Appwrite\Utopia\Response\Model\AttributeInteger; -use Appwrite\Utopia\Response\Model\AttributeFloat; use Appwrite\Utopia\Response\Model\AttributeBoolean; +use Appwrite\Utopia\Response\Model\AttributeDatetime; use Appwrite\Utopia\Response\Model\AttributeEmail; use Appwrite\Utopia\Response\Model\AttributeEnum; +use Appwrite\Utopia\Response\Model\AttributeFloat; +use Appwrite\Utopia\Response\Model\AttributeInteger; use Appwrite\Utopia\Response\Model\AttributeIP; -use Appwrite\Utopia\Response\Model\AttributeURL; -use Appwrite\Utopia\Response\Model\AttributeDatetime; +use Appwrite\Utopia\Response\Model\AttributeList; use Appwrite\Utopia\Response\Model\AttributeRelationship; +use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\AttributeURL; use Appwrite\Utopia\Response\Model\AuthProvider; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Branch; +use Appwrite\Utopia\Response\Model\Bucket; +use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\Collection; -use Appwrite\Utopia\Response\Model\Database; +use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Continent; use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; +use Appwrite\Utopia\Response\Model\Database; +use Appwrite\Utopia\Response\Model\Deployment; +use Appwrite\Utopia\Response\Model\Detection; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; -use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\File; -use Appwrite\Utopia\Response\Model\Bucket; -use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Func; -use Appwrite\Utopia\Response\Model\Identity; -use Appwrite\Utopia\Response\Model\Index; -use Appwrite\Utopia\Response\Model\JWT; -use Appwrite\Utopia\Response\Model\Key; -use Appwrite\Utopia\Response\Model\Language; -use Appwrite\Utopia\Response\Model\User; -use Appwrite\Utopia\Response\Model\Session; -use Appwrite\Utopia\Response\Model\Team; -use Appwrite\Utopia\Response\Model\Locale; -use Appwrite\Utopia\Response\Model\Log; -use Appwrite\Utopia\Response\Model\Membership; -use Appwrite\Utopia\Response\Model\Metric; -use Appwrite\Utopia\Response\Model\Phone; -use Appwrite\Utopia\Response\Model\Platform; -use Appwrite\Utopia\Response\Model\Project; -use Appwrite\Utopia\Response\Model\Deployment; -use Appwrite\Utopia\Response\Model\Detection; use Appwrite\Utopia\Response\Model\Headers; -use Appwrite\Utopia\Response\Model\TemplateEmail; -use Appwrite\Utopia\Response\Model\Token; -use Appwrite\Utopia\Response\Model\Webhook; -use Appwrite\Utopia\Response\Model\Preferences; use Appwrite\Utopia\Response\Model\HealthAntivirus; use Appwrite\Utopia\Response\Model\HealthCertificate; use Appwrite\Utopia\Response\Model\HealthQueue; use Appwrite\Utopia\Response\Model\HealthStatus; use Appwrite\Utopia\Response\Model\HealthTime; use Appwrite\Utopia\Response\Model\HealthVersion; -use Appwrite\Utopia\Response\Model\MFAChallenge; +use Appwrite\Utopia\Response\Model\Identity; +use Appwrite\Utopia\Response\Model\Index; use Appwrite\Utopia\Response\Model\Installation; +use Appwrite\Utopia\Response\Model\JWT; +use Appwrite\Utopia\Response\Model\Key; +use Appwrite\Utopia\Response\Model\Language; +use Appwrite\Utopia\Response\Model\Locale; use Appwrite\Utopia\Response\Model\LocaleCode; -use Appwrite\Utopia\Response\Model\MetricBreakdown; -use Appwrite\Utopia\Response\Model\Provider; +use Appwrite\Utopia\Response\Model\Log; +use Appwrite\Utopia\Response\Model\Membership; use Appwrite\Utopia\Response\Model\Message; +use Appwrite\Utopia\Response\Model\Metric; +use Appwrite\Utopia\Response\Model\MetricBreakdown; +use Appwrite\Utopia\Response\Model\MFAChallenge; use Appwrite\Utopia\Response\Model\MFAFactors; use Appwrite\Utopia\Response\Model\MFARecoveryCodes; use Appwrite\Utopia\Response\Model\MFAType; -use Appwrite\Utopia\Response\Model\Subscriber; -use Appwrite\Utopia\Response\Model\Topic; +use Appwrite\Utopia\Response\Model\Migration; +use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; +use Appwrite\Utopia\Response\Model\MigrationReport; +use Appwrite\Utopia\Response\Model\Mock; +use Appwrite\Utopia\Response\Model\None; +use Appwrite\Utopia\Response\Model\Phone; +use Appwrite\Utopia\Response\Model\Platform; +use Appwrite\Utopia\Response\Model\Preferences; +use Appwrite\Utopia\Response\Model\Project; +use Appwrite\Utopia\Response\Model\Provider; use Appwrite\Utopia\Response\Model\ProviderRepository; +use Appwrite\Utopia\Response\Model\Rule; use Appwrite\Utopia\Response\Model\Runtime; +use Appwrite\Utopia\Response\Model\Session; +use Appwrite\Utopia\Response\Model\Subscriber; use Appwrite\Utopia\Response\Model\Target; +use Appwrite\Utopia\Response\Model\Team; +use Appwrite\Utopia\Response\Model\TemplateEmail; use Appwrite\Utopia\Response\Model\TemplateSMS; +use Appwrite\Utopia\Response\Model\Token; +use Appwrite\Utopia\Response\Model\Topic; use Appwrite\Utopia\Response\Model\UsageBuckets; use Appwrite\Utopia\Response\Model\UsageCollection; use Appwrite\Utopia\Response\Model\UsageDatabase; @@ -99,13 +98,14 @@ use Appwrite\Utopia\Response\Model\UsageFunctions; use Appwrite\Utopia\Response\Model\UsageProject; use Appwrite\Utopia\Response\Model\UsageStorage; use Appwrite\Utopia\Response\Model\UsageUsers; +use Appwrite\Utopia\Response\Model\User; use Appwrite\Utopia\Response\Model\Variable; -use Appwrite\Utopia\Response\Model\Migration; -use Appwrite\Utopia\Response\Model\MigrationFirebaseProject; -use Appwrite\Utopia\Response\Model\MigrationReport; +use Appwrite\Utopia\Response\Model\Webhook; +use Exception; +use Swoole\Http\Response as SwooleHTTPResponse; // Keep last -use Appwrite\Utopia\Response\Model\Mock; -use Appwrite\Utopia\Response\Model\Rule; +use Utopia\Database\Document; +use Utopia\Swoole\Response as SwooleResponse; /** * @method int getStatusCode() @@ -299,9 +299,9 @@ class Response extends SwooleResponse public const MODEL_MOCK = 'mock'; /** - * @var Filter + * @var array */ - private static $filter = null; + protected array $filters = []; /** * @var array @@ -511,6 +511,15 @@ class Response extends SwooleResponse return $this->models; } + public function applyFilters(array $data, string $model): array + { + foreach ($this->filters as $filter) { + $data = $filter->parse($data, $model); + } + + return $data; + } + /** * Validate response objects and outputs * the response according to given format type @@ -524,11 +533,7 @@ class Response extends SwooleResponse public function dynamic(Document $document, string $model): void { $output = $this->output(clone $document, $model); - - // If filter is set, parse the output - if (self::hasFilter()) { - $output = self::getFilter()->parse($output, $model); - } + $output = $this->applyFilters($output, $model); switch ($this->getContentType()) { case self::CONTENT_TYPE_JSON: @@ -682,15 +687,15 @@ class Response extends SwooleResponse } /** - * Function to set a response filter + * Function to add a response filter, the order of filters are first in - first out. * * @param $filter the response filter to set * * @return void */ - public static function setFilter(?Filter $filter) + public function addFilter(Filter $filter): void { - self::$filter = $filter; + $this->filters[] = $filter; } /** @@ -698,9 +703,19 @@ class Response extends SwooleResponse * * @return Filter */ - public static function getFilter(): ?Filter + public function getFilters(): array { - return self::$filter; + return $this->filters; + } + + /** + * Reset filters + * + * @return void + */ + public function resetFilters(): void + { + $this->filters = []; } /** @@ -708,9 +723,9 @@ class Response extends SwooleResponse * * @return bool */ - public static function hasFilter(): bool + public function hasFilters(): bool { - return self::$filter != null; + return !empty($this->filters); } /** diff --git a/src/Appwrite/Utopia/Response/Filter.php b/src/Appwrite/Utopia/Response/Filter.php index 9110abd07a..bd82467f81 100644 --- a/src/Appwrite/Utopia/Response/Filter.php +++ b/src/Appwrite/Utopia/Response/Filter.php @@ -13,4 +13,25 @@ abstract class Filter * @return array */ abstract public function parse(array $content, string $model): array; + + + /** + * Handle list + * + * @param array $content + * @param string $key + * @param callable $callback + * + * @return array + */ + protected function handleList(array $content, string $key, callable $callback): array + { + if (array_key_exists($key, $content) && \is_array($content[$key])) { + foreach ($content[$key] as $i => $item) { + $content[$key][$i] = $callback($item); + } + } + + return $content; + } } diff --git a/src/Appwrite/Utopia/Response/Filters/V11.php b/src/Appwrite/Utopia/Response/Filters/V11.php deleted file mode 100644 index 8fa22f42b2..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V11.php +++ /dev/null @@ -1,401 +0,0 @@ -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' => ID::custom($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; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V12.php b/src/Appwrite/Utopia/Response/Filters/V12.php deleted file mode 100644 index 79d22ad044..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V12.php +++ /dev/null @@ -1,269 +0,0 @@ -parseError($content); - break; - - case Response::MODEL_SESSION: - $parsedResponse = $this->parseSession($content); - break; - case Response::MODEL_SESSION_LIST: - $parsedResponse = $this->parseSessionList($content); - break; - - case Response::MODEL_FILE: - $parsedResponse = $this->parseFile($content); - break; - case Response::MODEL_FILE_LIST: - $parsedResponse = $this->parseFileList($content); - break; - - case Response::MODEL_FUNCTION: - $parsedResponse = $this->parseFunction($content); - break; - case Response::MODEL_FUNCTION_LIST: - $parsedResponse = $this->parseFunctionList($content); - break; - - case Response::MODEL_DEPLOYMENT: - $parsedResponse = $this->parseDeployment($content); - break; - case Response::MODEL_DEPLOYMENT_LIST: - $parsedResponse = $this->parseDeploymentList($content); - break; - - case Response::MODEL_EXECUTION: - $parsedResponse = $this->parseExecution($content); - break; - case Response::MODEL_EXECUTION_LIST: - $parsedResponse = $this->parseExecutionList($content); - break; - - case Response::MODEL_USAGE_BUCKETS: - $parsedResponse = $this->parseUsageBuckets($content); - break; - - case Response::MODEL_USAGE_STORAGE: - $parsedResponse = $this->parseUsageStorage($content); - break; - - case Response::MODEL_TEAM: - $parsedResponse = $this->parseTeam($content); - break; - case Response::MODEL_TEAM_LIST: - $parsedResponse = $this->parseTeamList($content); - break; - - case Response::MODEL_DOCUMENT_LIST: - case Response::MODEL_COLLECTION_LIST: - case Response::MODEL_INDEX_LIST: - case Response::MODEL_USER_LIST: - case Response::MODEL_LOG_LIST: - case Response::MODEL_BUCKET_LIST: - case Response::MODEL_MEMBERSHIP_LIST: - case Response::MODEL_RUNTIME_LIST: - case Response::MODEL_BUILD_LIST: - case Response::MODEL_PROJECT_LIST: - case Response::MODEL_WEBHOOK_LIST: - case Response::MODEL_KEY_LIST: - case Response::MODEL_PLATFORM_LIST: - case Response::MODEL_DOMAIN_LIST: - case Response::MODEL_COUNTRY_LIST: - case Response::MODEL_CONTINENT_LIST: - case Response::MODEL_LANGUAGE_LIST: - case Response::MODEL_CURRENCY_LIST: - case Response::MODEL_PHONE_LIST: - case Response::MODEL_METRIC_LIST: - case Response::MODEL_ATTRIBUTE_LIST: - $parsedResponse = $this->parseList($content); - break; - } - - return $parsedResponse; - } - - protected function parseError(array $content) - { - unset($content['type']); - return $content; - } - - protected function parseSession(array $content) - { - $content['providerToken'] = $content['providerAccessToken']; - unset($content['providerAccessToken']); - - unset($content['providerAccessTokenExpiry']); - - unset($content['providerRefreshToken']); - - return $content; - } - - protected function parseSessionList(array $content) - { - $sessions = $content['sessions']; - $parsedResponse = []; - foreach ($sessions as $document) { - $parsedResponse[] = $this->parseSession($document); - } - $content['sessions'] = $parsedResponse; - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseFile(array $content) - { - unset($content['bucketId']); - unset($content['chunksTotal']); - unset($content['chunksUploaded']); - - return $content; - } - - protected function parseFileList(array $content) - { - $files = $content['files']; - $parsedResponse = []; - foreach ($files as $document) { - $parsedResponse[] = $this->parseFile($document); - } - $content['files'] = $parsedResponse; - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseFunction(array $content) - { - $content['tag'] = $content['deployment']; - unset($content['deployment']); - return $content; - } - - protected function parseFunctionList(array $content) - { - $functions = $content['functions']; - $parsedResponse = []; - foreach ($functions as $document) { - $parsedResponse[] = $this->parseFunction($document); - } - $content['functions'] = $parsedResponse; - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseDeployment(array $content) - { - $content['functionId'] = $content['resourceId']; - $content['command'] = $content['entrypoint']; - return $content; - } - - protected function parseDeploymentList(array $content) - { - $deployments = $content['deployments']; - $parsedResponse = []; - foreach ($deployments as $document) { - $parsedResponse[] = $this->parseDeployment($document); - } - $content['deployments'] = $parsedResponse; - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseUsageBuckets(array $content) - { - unset($content['filesStorage']); - return $content; - } - - protected function parseUsageStorage(array $content) - { - $content['storage'] = $content['filesStorage']; - unset($content['filesStorage']); - - $content['files'] = $content['tagsStorage']; - unset($content['tagsStorage']); - - unset($content['filesCount']); - unset($content['bucketsCount']); - unset($content['bucketsCreate']); - unset($content['bucketsRead']); - unset($content['bucketsUpdate']); - unset($content['bucketsDelete']); - unset($content['filesCount']); - unset($content['bucketsDelete']); - unset($content['filesCreate']); - unset($content['filesRead']); - unset($content['filesUpdate']); - unset($content['filesDelete']); - - return $content; - } - - protected function parseExecution($content) - { - $content['exitCode'] = $content['statusCode']; - unset($content['statusCode']); - - return $content; - } - - protected function parseExecutionList($content) - { - $executions = $content['executions']; - $parsedResponse = []; - foreach ($executions as $document) { - $parsedResponse[] = $this->parseExecution($document); - } - $content['executions'] = $parsedResponse; - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseTeam($content) - { - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseTeamList($content) - { - $teams = $content['teams']; - $parsedResponse = []; - foreach ($teams as $document) { - $parsedResponse[] = $this->parseTeam($document); - } - $content['teams'] = $parsedResponse; - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } - - protected function parseList($content) - { - $content['sum'] = $content['total']; - unset($content['total']); - return $content; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V13.php b/src/Appwrite/Utopia/Response/Filters/V13.php deleted file mode 100644 index 04f9782915..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V13.php +++ /dev/null @@ -1,103 +0,0 @@ -parseProject($content); - break; - - case Response::MODEL_PROJECT_LIST: - $parsedResponse = $this->parseProjectList($content); - break; - - case Response::MODEL_MEMBERSHIP: - $parsedResponse = $this->parseMembership($content); - break; - case Response::MODEL_MEMBERSHIP_LIST: - $parsedResponse = $this->parseMembershipList($content); - break; - - case Response::MODEL_EXECUTION: - $parsedResponse = $this->parseExecution($content); - break; - case Response::MODEL_EXECUTION_LIST: - $parsedResponse = $this->parseExecutionList($content); - break; - } - - return $parsedResponse; - } - - protected function parseExecution($content) - { - $content['stdout'] = $content['response']; - unset($content['response']); - - return $content; - } - - protected function parseExecutionList($content) - { - $executions = $content['executions']; - $parsedResponse = []; - foreach ($executions as $document) { - $parsedResponse[] = $this->parseExecution($document); - } - $content['executions'] = $parsedResponse; - return $content; - } - - protected function parseProject($content) - { - $content['providers'] = $content['oAuthProviders']; - unset($content['oAuthProviders']); - - return $content; - } - - protected function parseProjectList($content) - { - $projects = $content['projects']; - $parsedResponse = []; - foreach ($projects as $document) { - $parsedResponse[] = $this->parseProject($document); - } - $content['projects'] = $parsedResponse; - return $content; - } - - protected function parseMembership($content) - { - $content['name'] = $content['userName']; - unset($content['userName']); - - $content['email'] = $content['userEmail']; - unset($content['userEmail']); - - unset($content['teamName']); - - return $content; - } - - protected function parseMembershipList($content) - { - $memberships = $content['memberships']; - $parsedResponse = []; - foreach ($memberships as $document) { - $parsedResponse[] = $this->parseMembership($document); - } - $content['memberships'] = $parsedResponse; - return $content; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V14.php b/src/Appwrite/Utopia/Response/Filters/V14.php deleted file mode 100644 index 200823f37f..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V14.php +++ /dev/null @@ -1,176 +0,0 @@ -parseRemoveAttributes($content, ['$createdAt']); - - break; - case Response::MODEL_SESSION_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'domains', ['$createdAt']); - - break; - case Response::MODEL_DOCUMENT: - case Response::MODEL_DOMAIN: - case Response::MODEL_FUNCTION: - case Response::MODEL_TEAM: - case Response::MODEL_MEMBERSHIP: - case Response::MODEL_PLATFORM: - case Response::MODEL_PROJECT: - case Response::MODEL_USER: - case Response::MODEL_WEBHOOK: - $parsedResponse = $this->parseRemoveAttributes($content, ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_DOCUMENT_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'documents', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_DOMAIN_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'domains', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_FUNCTION_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'functions', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_TEAM_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'teams', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_MEMBERSHIP_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'memberships', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_PLATFORM_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'platforms', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_PROJECT_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'projects', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_USER_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'users', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_WEBHOOK_LIST: - $parsedResponse = $this->parseRemoveAttributesList($content, 'webhooks', ['$createdAt', '$updatedAt']); - - break; - case Response::MODEL_TEAM: - case Response::MODEL_EXECUTION: - case Response::MODEL_FILE: - $parsedResponse = $this->parseCreatedAt($content); - break; - - case Response::MODEL_TEAM_LIST: - $parsedResponse = $this->parseCreatedAtList($content, 'teams'); - break; - - case Response::MODEL_EXECUTION_LIST: - $parsedResponse = $this->parseCreatedAtList($content, 'executions'); - break; - - case Response::MODEL_FILE_LIST: - $parsedResponse = $this->parseCreatedAtList($content, 'files'); - break; - - case Response::MODEL_FUNCTION: - case Response::MODEL_DEPLOYMENT: - case Response::MODEL_BUCKET: - $parsedResponse = $this->parseCreatedAtAndUpdatedAt($content); - break; - - case Response::MODEL_FUNCTION_LIST: - $parsedResponse = $this->parseCreatedAtAndUpdatedAtList($content, 'functions'); - break; - - case Response::MODEL_DEPLOYMENT_LIST: - $parsedResponse = $this->parseCreatedAtAndUpdatedAtList($content, 'deployments'); - break; - - case Response::MODEL_BUCKET_LIST: - $parsedResponse = $this->parseCreatedAtAndUpdatedAtList($content, 'buckets'); - break; - } - - return $parsedResponse; - } - - protected function parseRemoveAttributes(array $content, array $attributes) - { - foreach ($attributes as $attribute) { - unset($content[$attribute]); - } - - return $content; - } - - protected function parseRemoveAttributesList(array $content, string $property, array $attributes) - { - $documents = $content[$property]; - $parsedResponse = []; - foreach ($documents as $document) { - $parsedResponse[] = $this->parseRemoveAttributes($document, $attributes); - } - $content[$property] = $parsedResponse; - - return $content; - } - - protected function parseCreatedAt(array $content) - { - $content['dateCreated'] = $content['$createdAt']; - unset($content['$createdAt']); - unset($content['$updatedAt']); - - return $content; - } - - protected function parseCreatedAtList(array $content, string $property) - { - $documents = $content[$property]; - $parsedResponse = []; - foreach ($documents as $document) { - $parsedResponse[] = $this->parseCreatedAt($document); - } - $content[$property] = $parsedResponse; - - return $content; - } - - protected function parseCreatedAtAndUpdatedAt(array $content) - { - $content['dateCreated'] = $content['$createdAt']; - $content['dateUpdated'] = $content['$updatedAt']; - unset($content['$createdAt']); - unset($content['$updatedAt']); - - return $content; - } - - protected function parseCreatedAtAndUpdatedAtList(array $content, string $property) - { - $documents = $content[$property]; - $parsedResponse = []; - foreach ($documents as $document) { - $parsedResponse[] = $this->parseCreatedAtAndUpdatedAt($document); - } - $content[$property] = $parsedResponse; - - return $content; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php deleted file mode 100644 index 232feec201..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ /dev/null @@ -1,591 +0,0 @@ -parseUser($parsedResponse); - break; - case Response::MODEL_USER_LIST: - $listKey = 'users'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseUser($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_METRIC: - $parsedResponse = $this->parseMetric($parsedResponse); - break; - case Response::MODEL_BUILD: - $parsedResponse = $this->parseBuild($parsedResponse); - break; - case Response::MODEL_BUILD_LIST: - $listKey = 'builds'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseBuild($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_BUCKET: - $parsedResponse = $this->parseBucket($parsedResponse); - break; - case Response::MODEL_BUCKET_LIST: - $listKey = 'buckets'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseBucket($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_COLLECTION: - $parsedResponse = $this->parseCollection($parsedResponse); - break; - case Response::MODEL_COLLECTION_LIST: - $listKey = 'collections'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseCollection($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_DATABASE: - case Response::MODEL_DEPLOYMENT: - case Response::MODEL_DOMAIN: - case Response::MODEL_PLATFORM: - case Response::MODEL_PROJECT: - case Response::MODEL_TEAM: - case Response::MODEL_WEBHOOK: - $parsedResponse = $this->parseCreatedAtUpdatedAt($parsedResponse); - break; - case Response::MODEL_DATABASE_LIST: - case Response::MODEL_DEPLOYMENT_LIST: - case Response::MODEL_DOMAIN_LIST: - case Response::MODEL_PLATFORM_LIST: - case Response::MODEL_PROJECT_LIST: - case Response::MODEL_TEAM_LIST: - case Response::MODEL_WEBHOOK_LIST: - $listKey = ''; - switch ($model) { - case Response::MODEL_DATABASE_LIST: - $listKey = 'databases'; - break; - case Response::MODEL_DEPLOYMENT_LIST: - $listKey = 'deployments'; - break; - case Response::MODEL_DOMAIN_LIST: - $listKey = 'domains'; - break; - case Response::MODEL_PLATFORM_LIST: - $listKey = 'platforms'; - break; - case Response::MODEL_PROJECT_LIST: - $listKey = 'projects'; - break; - case Response::MODEL_TEAM_LIST: - $listKey = 'teams'; - break; - case Response::MODEL_WEBHOOK_LIST: - $listKey = 'webhooks'; - break; - } - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseCreatedAtUpdatedAt($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_DOCUMENT: - $parsedResponse = $this->parseDocument($parsedResponse); - break; - case Response::MODEL_FILE: - $parsedResponse = $this->parsePermissionsCreatedAtUpdatedAt($parsedResponse); - break; - case Response::MODEL_DOCUMENT_LIST: - $listKey = 'documents'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseDocument($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_FILE_LIST: - $listKey = 'files'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parsePermissionsCreatedAtUpdatedAt($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_EXECUTION: - $parsedResponse = $this->parseExecution($parsedResponse); - break; - case Response::MODEL_EXECUTION_LIST: - $listKey = 'executions'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseExecution($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_FUNCTION: - $parsedResponse = $this->parseFunction($parsedResponse); - break; - case Response::MODEL_FUNCTION_LIST: - $listKey = 'functions'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseFunction($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_KEY: - $parsedResponse = $this->parseKey($parsedResponse); - break; - case Response::MODEL_KEY_LIST: - $listKey = 'keys'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseKey($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_LOG: - $parsedResponse = $this->parseLog($parsedResponse); - break; - case Response::MODEL_LOG_LIST: - $listKey = 'logs'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseLog($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_MEMBERSHIP: - $parsedResponse = $this->parseMembership($parsedResponse); - break; - case Response::MODEL_MEMBERSHIP_LIST: - $listKey = 'memberships'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseMembership($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_SESSION: - $parsedResponse = $this->parseSession($parsedResponse); - break; - case Response::MODEL_SESSION_LIST: - $listKey = 'sessions'; - $parsedResponse[$listKey] = array_map(fn ($content) => $this->parseSession($content), $parsedResponse[$listKey]); - break; - case Response::MODEL_TOKEN: - $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', 'expire']); - break; - case Response::MODEL_USAGE_DATABASES: - $parsedResponse = $this->parseUsageDatabases($parsedResponse); - break; - case Response::MODEL_USAGE_DATABASE: - $parsedResponse = $this->parseUsageDatabase($parsedResponse); - break; - case Response::MODEL_USAGE_COLLECTION: - $parsedResponse = $this->parseUsageCollection($parsedResponse); - break; - case Response::MODEL_USAGE_USERS: - $parsedResponse = $this->parseUsageUsers($parsedResponse); - break; - case Response::MODEL_USAGE_BUCKETS: - $parsedResponse = $this->parseUsageBuckets($parsedResponse); - break; - case Response::MODEL_USAGE_FUNCTIONS: - $parsedResponse = $this->parseUsageFuncs($parsedResponse); - break; - case Response::MODEL_USAGE_PROJECT: - $parsedResponse = $this->parseUsageProject($parsedResponse); - break; - case Response::MODEL_USAGE_STORAGE: - $parsedResponse = $this->parseUsageStorage($parsedResponse); - break; - } - - return $parsedResponse; - } - - protected function parseBuild(array $content) - { - $content = $this->parseDatetimeAttributes($content, ['startTime', 'endTime']); - - return $content; - } - - protected function parseBucket(array $content) - { - if (isset($content['fileSecurity'])) { - if ($content['fileSecurity']) { - $content['permission'] = 'file'; - } else { - $content['permission'] = 'bucket'; - } - } - - unset($content['fileSecurity']); - unset($content['compression']); - - $content = $this->parsePermissions($content); - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - - return $content; - } - - protected function parseDatetimeAttributes(array $content, array $attributes): array - { - foreach ($attributes as $attribute) { - if (array_key_exists($attribute, $content)) { - if (empty($content[$attribute])) { - $content[$attribute] = 0; - continue; - } - $content[$attribute] = strtotime($content[$attribute]); - } - } - return $content; - } - - protected function parseUser(array $content): array - { - unset($content['password']); - unset($content['hash']); - unset($content['hashOptions']); - - $content = $this->parseDatetimeAttributes($content, ['registration', 'passwordUpdate', '$createdAt', '$updatedAt']); - return $content; - } - - protected function parseMetric(array $content) - { - $content = $this->parseDatetimeAttributes($content, ['date']); - return $content; - } - - protected function parsePermissions(array $content) - { - if (!isset($content['$permissions'])) { - return $content; - } - - $read = []; - $write = []; - - // downgrade the permissions - foreach ($content['$permissions'] as $permission) { - $permission = Permission::parse($permission); - $permission_value = $permission->getRole(); - if ($permission->getIdentifier()) { - $permission_value .= ':' . $permission->getIdentifier(); - } - if ($permission->getDimension()) { - $permission_value .= '/' . $permission->getDimension(); - } - - // Old type permissions meant that 'write' is equivalent to 'create', 'update' and 'delete' - switch ($permission->getPermission()) { - case Database::PERMISSION_UPDATE: - case Database::PERMISSION_DELETE: - case Database::PERMISSION_WRITE: - case Database::PERMISSION_CREATE: - $write[$this->parseRole($permission_value)] = true; - break; - case Database::PERMISSION_READ: - $read[$this->parseRole($permission_value)] = true; - break; - } - } - - $content['$read'] = array_keys($read); - $content['$write'] = array_keys($write); - - unset($content['$permissions']); - - return $content; - } - - protected function parseRole(string $role) - { - switch ($role) { - case Role::any()->toString(): - return 'role:all'; - case Role::users()->toString(): - return 'role:member'; - case Role::guests()->toString(): - return 'role:guest'; - default: - return $role; - } - - return $role; - } - - protected function parseCollection(array $content) - { - if (isset($content['documentSecurity'])) { - if ($content['documentSecurity']) { - $content['permission'] = 'document'; - } else { - $content['permission'] = 'collection'; - } - } - - unset($content['documentSecurity']); - $content = $this->parsePermissions($content); - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - return $content; - } - - protected function parsePermissionsCreatedAtUpdatedAt(array $content) - { - $content = $this->parsePermissions($content); - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - return $content; - } - - protected function parseDocument(array $content) - { - if (isset($content['$collectionId'])) { - $content['$collection'] = $content['$collectionId']; - unset($content['$collectionId']); - } - - unset($content['$databaseId']); - - $content = $this->parsePermissionsCreatedAtUpdatedAt($content); - return $content; - } - - private function parseExecution($content) - { - unset($content['stdout']); - - if (isset($content['$permissions'])) { - $read = []; - foreach ($content['$permissions'] as $role) { - $read[] = $this->parseRole($role); - } - $content['$read'] = $read; - unset($content['$permissions']); - } - - if (isset($content['duration'])) { - $content['time'] = $content['duration']; - unset($content['duration']); - } - - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - - return $content; - } - - private function parseCreatedAtUpdatedAt($content) - { - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); - return $content; - } - - private function parseFunction($content) - { - if (isset($content['execute'])) { - foreach ($content['execute'] as $i => $role) { - $content['execute'][$i] = $this->parseRole($role); - } - } - - if (isset($content['vars'])) { - $vars = []; - foreach ($content['vars'] as $i => $var) { - $vars[$var['key']] = $var['value']; - } - $content['vars'] = $vars; - } - - if (isset($content['enabled'])) { - $content['status'] = $content['enabled'] ? 'enabled' : 'disabled'; - unset($content['enabled']); - } - - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'scheduleNext', 'schedulePrevious']); - - return $content; - } - - private function parseKey($content) - { - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); - return $content; - } - - private function parseLog($content) - { - $content = $this->parseDatetimeAttributes($content, ['time']); - return $content; - } - - private function parseMembership($content) - { - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'invited', 'joined']); - return $content; - } - - private function parseSession($content) - { - $content = $this->parseDatetimeAttributes($content, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); - return $content; - } - - private function parseUsage($content, $keys) - { - foreach ($keys as $key) { - $data = []; - foreach ($content[$key] as $metric) { - $data[] = $this->parseMetric($metric); - } - $content[$key] = $data; - } - - return $content; - } - - private function parseUsageDatabases($content) - { - $keys = [ - 'databasesCount', - 'documentsCount', - 'collectionsCount', - 'databasesCreate', - 'databasesRead', - 'databasesUpdate', - 'databasesDelete', - 'documentsCreate', - 'documentsRead', - 'documentsUpdate', - 'documentsDelete', - 'collectionsCreate', - 'collectionsRead', - 'collectionsUpdate', - 'collectionsDelete', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } - - private function parseUsageDatabase($content) - { - $keys = [ - 'documentsCount', - 'collectionsCount', - 'documentsCreate', - 'documentsRead', - 'documentsUpdate', - 'documentsDelete', - 'collectionsCreate', - 'collectionsRead', - 'collectionsUpdate', - 'collectionsDelete', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } - - private function parseUsageCollection($content) - { - $keys = [ - 'documentsCount', - 'documentsCreate', - 'documentsRead', - 'documentsUpdate', - 'documentsDelete', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } - - private function parseUsageUsers($content) - { - $keys = [ - 'usersCount', - 'usersCreate', - 'usersRead', - 'usersUpdate', - 'usersDelete', - 'sessionsCreate', - 'sessionsProviderCreate', - 'sessionsDelete', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } - - private function parseUsageBuckets($content) - { - $keys = [ - 'filesCount', - 'filesStorage', - 'filesCreate', - 'filesRead', - 'filesUpdate', - 'filesDelete', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } - - private function parseUsageFuncs($content) - { - $mapping = [ - 'executionsTotal' => 'functionsExecutions', - 'executionsFailure' => 'functionsFailures', - 'executionsTime' => 'functionsCompute', - ]; - - foreach ($mapping as $new => $old) { - if (isset($content[$new])) { - $data = []; - foreach ($content[$new] as $metric) { - $data[] = $this->parseMetric($metric); - } - $content[$old] = $data; - unset($content[$new]); - } - } - - unset($content['functionExecutions']); - unset($content['functionFailure']); - unset($content['executionsTime']); - unset($content['buildsTotal']); - unset($content['executionsSuccess']); - unset($content['buildsFailure']); - unset($content['buildsSuccess']); - unset($content['buildsTime']); - - return $content; - } - - private function parseUsageProject($content) - { - $content['functions'] = $content['executions']; - unset($content['executions']); - - $keys = [ - 'collections', - 'documents', - 'functions', - 'network', - 'requests', - 'storage', - 'users', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } - - private function parseUsageStorage($content) - { - $content['filesStorage'] = $content['storage']; - unset($content['storage']); - - $keys = [ - 'bucketsCount', - 'bucketsCreate', - 'bucketsDelete', - 'bucketsRead', - 'bucketsUpdate', - 'filesCount', - 'filesCreate', - 'filesDelete', - 'filesRead', - 'filesStorage', - 'filesUpdate', - ]; - - $content = $this->parseUsage($content, $keys); - - return $content; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V16.php b/src/Appwrite/Utopia/Response/Filters/V16.php index 609f118f6e..0d04ac8b97 100644 --- a/src/Appwrite/Utopia/Response/Filters/V16.php +++ b/src/Appwrite/Utopia/Response/Filters/V16.php @@ -14,27 +14,19 @@ class V16 extends Filter { $parsedResponse = $content; - switch ($model) { - case Response::MODEL_DEPLOYMENT: - $parsedResponse = $this->parseDeployment($parsedResponse); - break; - case Response::MODEL_PROXY_RULE: - // We won't be supporting the domain endpoints for older SDKs - // since these APIs are internal. As such, no filtering required - break; - case Response::MODEL_EXECUTION: - $parsedResponse = $this->parseExecution($parsedResponse); - break; - case Response::MODEL_FUNCTION: - $parsedResponse = $this->parseFunction($parsedResponse); - break; - case Response::MODEL_PROJECT: - $parsedResponse = $this->parseProject($parsedResponse); - break; - case Response::MODEL_VARIABLE: - $parsedResponse = $this->parseVariable($parsedResponse); - break; - } + $parsedResponse = match($model) { + Response::MODEL_DEPLOYMENT => $this->parseDeployment($parsedResponse), + Response::MODEL_DEPLOYMENT_LIST => $this->handleList($content, 'deployments', fn ($item) => $this->parseDeployment($item)), + Response::MODEL_EXECUTION => $this->parseExecution($parsedResponse), + Response::MODEL_EXECUTION_LIST => $this->handleList($content, 'executions', fn ($item) => $this->parseExecution($item)), + Response::MODEL_FUNCTION => $this->parseFunction($parsedResponse), + Response::MODEL_FUNCTION_LIST => $this->handleList($content, 'functions', fn ($item) => $this->parseFunction($item)), + Response::MODEL_PROJECT => $this->parseProject($parsedResponse), + Response::MODEL_PROJECT_LIST => $this->handleList($content, 'projects', fn ($item) => $this->parseProject($item)), + Response::MODEL_VARIABLE => $this->parseVariable($parsedResponse), + Response::MODEL_VARIABLE_LIST => $this->handleList($content, 'variables', fn ($item) => $this->parseVariable($item)), + default => $parsedResponse, + }; return $parsedResponse; } diff --git a/src/Appwrite/Utopia/Response/Filters/V17.php b/src/Appwrite/Utopia/Response/Filters/V17.php index 75fff719cc..75821de160 100644 --- a/src/Appwrite/Utopia/Response/Filters/V17.php +++ b/src/Appwrite/Utopia/Response/Filters/V17.php @@ -12,26 +12,20 @@ class V17 extends Filter { $parsedResponse = $content; - switch ($model) { - case Response::MODEL_PROJECT: - $parsedResponse = $this->parseProject($parsedResponse); - break; - case Response::MODEL_USER: - $parsedResponse = $this->parseUser($parsedResponse); - break; - case Response::MODEL_TOKEN: - $parsedResponse = $this->parseToken($parsedResponse); - break; - case Response::MODEL_MEMBERSHIP: - $parsedResponse = $this->parseMembership($parsedResponse); - break; - case Response::MODEL_SESSION: - $parsedResponse = $this->parseSession($parsedResponse); - break; - case Response::MODEL_WEBHOOK: - $parsedResponse = $this->parseWebhook($parsedResponse); - break; - } + $parsedResponse = match($model) { + Response::MODEL_PROJECT => $this->parseProject($parsedResponse), + Response::MODEL_PROJECT_LIST => $this->handleList($content, 'projects', fn ($item) => $this->parseProject($item)), + Response::MODEL_USER => $this->parseUser($parsedResponse), + Response::MODEL_USER_LIST => $this->handleList($content, 'users', fn ($item) => $this->parseUser($item)), + Response::MODEL_MEMBERSHIP => $this->parseMembership($parsedResponse), + Response::MODEL_MEMBERSHIP_LIST => $this->handleList($content, 'memberships', fn ($item) => $this->parseMembership($item)), + Response::MODEL_SESSION => $this->parseSession($parsedResponse), + Response::MODEL_SESSION_LIST => $this->handleList($content, 'sessions', fn ($item) => $this->parseSession($item)), + Response::MODEL_WEBHOOK => $this->parseWebhook($parsedResponse), + Response::MODEL_WEBHOOK_LIST => $this->handleList($content, 'webhooks', fn ($item) => $this->parseWebhook($item)), + Response::MODEL_TOKEN => $this->parseToken($parsedResponse), + default => $parsedResponse, + }; return $parsedResponse; } diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index 3ff171dfff..fbd9619a40 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -84,7 +84,7 @@ class Execution extends Model 'description' => 'HTTP response body. This will return empty unless execution is created as synchronous.', 'default' => '', 'example' => 'Developers are awesome.', - ]) + ]) ->addRule('responseHeaders', [ 'type' => Response::MODEL_HEADERS, 'description' => 'HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.', diff --git a/src/Appwrite/Utopia/Response/Model/Func.php b/src/Appwrite/Utopia/Response/Model/Func.php index e32735b38e..0c8d4d42d2 100644 --- a/src/Appwrite/Utopia/Response/Model/Func.php +++ b/src/Appwrite/Utopia/Response/Model/Func.php @@ -4,8 +4,6 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; -use stdClass; -use Utopia\Database\Document; class Func extends Model { diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index f6502bd75a..e52b6836c5 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -5,7 +5,6 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\DateTime; -use Utopia\Database\Document as DatabaseDocument; class Message extends Model { diff --git a/src/Appwrite/Utopia/Response/Model/Rule.php b/src/Appwrite/Utopia/Response/Model/Rule.php index 077455b4a7..932591b90f 100644 --- a/src/Appwrite/Utopia/Response/Model/Rule.php +++ b/src/Appwrite/Utopia/Response/Model/Rule.php @@ -4,8 +4,6 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; -use stdClass; -use Utopia\Database\Document; class Rule extends Model { diff --git a/src/Appwrite/Vcs/Comment.php b/src/Appwrite/Vcs/Comment.php index 1107e0ee70..35f76b6fd0 100644 --- a/src/Appwrite/Vcs/Comment.php +++ b/src/Appwrite/Vcs/Comment.php @@ -2,8 +2,8 @@ namespace Appwrite\Vcs; -use Utopia\Database\Document; use Utopia\App; +use Utopia\Database\Document; class Comment { diff --git a/tests/e2e/General/HooksTest.php b/tests/e2e/General/HooksTest.php index f4933428d1..d67c3256d9 100644 --- a/tests/e2e/General/HooksTest.php +++ b/tests/e2e/General/HooksTest.php @@ -70,63 +70,63 @@ class HooksTest extends Scope /** * Setup blocked user */ - $email = uniqid() . 'user@localhost.test'; - $password = 'password'; + $email = uniqid() . 'user@localhost.test'; + $password = 'password'; - $response = $this->client->call(Client::METHOD_POST, '/v1/account', [ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - ]); - - $id = $response['body']['$id']; - - $this->assertEquals(201, $response['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_POST, '/v1/account/sessions/email', [ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], [ - 'email' => $email, - 'password' => $password, - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - - $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; - $cookie = 'a_session_' . $this->getProject()['$id'] . '=' . $session; - - $response = $this->client->call(Client::METHOD_GET, '/v1/account', [ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_PATCH, '/v1/account/status', [ + $response = $this->client->call(Client::METHOD_POST, '/v1/account', [ 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - ], [ - 'status' => false, - ]); + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], [ + 'userId' => ID::unique(), + 'email' => $email, + 'password' => $password, + ]); - $this->assertEquals(200, $response['headers']['status-code']); + $id = $response['body']['$id']; - $response = $this->client->call(Client::METHOD_GET, '/v1/account', [ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => $cookie, - ]); + $this->assertEquals(201, $response['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_POST, '/v1/account/sessions/email', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], [ + 'email' => $email, + 'password' => $password, + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + + $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; + $cookie = 'a_session_' . $this->getProject()['$id'] . '=' . $session; + + $response = $this->client->call(Client::METHOD_GET, '/v1/account', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/v1/account/status', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ], [ + 'status' => false, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_GET, '/v1/account', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => $cookie, + ]); $this->assertEquals(401, $response['headers']['status-code']); diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 7df5143ecf..59df8b6420 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -3,12 +3,12 @@ namespace Tests\E2E\General; use Appwrite\Tests\Retry; +use CURLFile; +use DateTime; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use CURLFile; -use DateTime; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php index ed405cb7c0..3213ff4c5d 100644 --- a/tests/e2e/Scopes/Scope.php +++ b/tests/e2e/Scopes/Scope.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Scopes; use Appwrite\Tests\Retryable; -use Tests\E2E\Client; use PHPUnit\Framework\TestCase; +use Tests\E2E\Client; use Utopia\Database\Helpers\ID; abstract class Scope extends TestCase diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index ebb9ea644c..d61f44ca1b 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Account; use Tests\E2E\Client; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; -use Utopia\Database\Query; trait AccountBase { @@ -277,43 +276,43 @@ trait AccountBase public function testDeleteAccount(): void { - $email = uniqid() . 'user@localhost.test'; - $password = 'password'; - $name = 'User Name'; + $email = uniqid() . 'user@localhost.test'; + $password = 'password'; + $name = 'User Name'; - $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - ]); + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'userId' => ID::unique(), + 'email' => $email, + 'password' => $password, + 'name' => $name, + ]); - $this->assertEquals($response['headers']['status-code'], 201); + $this->assertEquals($response['headers']['status-code'], 201); - $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'email' => $email, - 'password' => $password, - ]); + $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'email' => $email, + 'password' => $password, + ]); - $this->assertEquals($response['headers']['status-code'], 201); + $this->assertEquals($response['headers']['status-code'], 201); - $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; + $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; - $response = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); + $response = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); - $this->assertEquals($response['headers']['status-code'], 204); + $this->assertEquals($response['headers']['status-code'], 204); } } diff --git a/tests/e2e/Services/Account/AccountConsoleClientTest.php b/tests/e2e/Services/Account/AccountConsoleClientTest.php index 97a3374536..1df9ef6c18 100644 --- a/tests/e2e/Services/Account/AccountConsoleClientTest.php +++ b/tests/e2e/Services/Account/AccountConsoleClientTest.php @@ -2,10 +2,10 @@ namespace Tests\E2E\Services\Account; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectConsole; -use Tests\E2E\Scopes\SideClient; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; class AccountConsoleClientTest extends Scope @@ -16,76 +16,76 @@ class AccountConsoleClientTest extends Scope public function testDeleteAccount(): void { - $email = uniqid() . 'user@localhost.test'; - $password = 'password'; - $name = 'User Name'; + $email = uniqid() . 'user@localhost.test'; + $password = 'password'; + $name = 'User Name'; - $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'userId' => ID::unique(), - 'email' => $email, - 'password' => $password, - 'name' => $name, - ]); - - $this->assertEquals($response['headers']['status-code'], 201); - - $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ]), [ - 'email' => $email, - 'password' => $password, - ]); - - $this->assertEquals($response['headers']['status-code'], 201); - - $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; - - // create team - $team = $this->client->call(Client::METHOD_POST, '/teams', [ + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'userId' => ID::unique(), + 'email' => $email, + 'password' => $password, + 'name' => $name, + ]); + + $this->assertEquals($response['headers']['status-code'], 201); + + $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]), [ + 'email' => $email, + 'password' => $password, + ]); + + $this->assertEquals($response['headers']['status-code'], 201); + + $session = $response['cookies']['a_session_' . $this->getProject()['$id']]; + + // create team + $team = $this->client->call(Client::METHOD_POST, '/teams', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ], [ 'teamId' => 'unique()', 'name' => 'myteam' - ]); - $this->assertEquals($team['headers']['status-code'], 201); + ]); + $this->assertEquals($team['headers']['status-code'], 201); - $teamId = $team['body']['$id']; + $teamId = $team['body']['$id']; - $response = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); + $response = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); - $this->assertEquals($response['headers']['status-code'], 400); + $this->assertEquals($response['headers']['status-code'], 400); - // DELETE TEAM - $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamId, array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); - $this->assertEquals($response['headers']['status-code'], 204); - sleep(2); + // DELETE TEAM + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamId, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); + $this->assertEquals($response['headers']['status-code'], 204); + sleep(2); - $response = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); + $response = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); - $this->assertEquals($response['headers']['status-code'], 204); + $this->assertEquals($response['headers']['status-code'], 204); } } diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 7e713cfb74..23771712e8 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Account; use Appwrite\Tests\Retry; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; diff --git a/tests/e2e/Services/Account/AccountCustomServerTest.php b/tests/e2e/Services/Account/AccountCustomServerTest.php index e29110cf42..eb72a99913 100644 --- a/tests/e2e/Services/Account/AccountCustomServerTest.php +++ b/tests/e2e/Services/Account/AccountCustomServerTest.php @@ -6,8 +6,8 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Helpers\ID; +use Utopia\Database\Validator\Datetime as DatetimeValidator; class AccountCustomServerTest extends Scope { @@ -112,7 +112,7 @@ class AccountCustomServerTest extends Scope ]); } - /** + /** * @depends testCreateAccountSession */ public function testGetAccount($data): array diff --git a/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php b/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php index a59d694114..bfd17ef1e9 100644 --- a/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php +++ b/tests/e2e/Services/Avatars/AvatarsConsoleClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Avatars; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class AvatarsConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php b/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php index dc399971a0..edf09d5ba1 100644 --- a/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php +++ b/tests/e2e/Services/Avatars/AvatarsCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Avatars; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class AvatarsCustomClientTest extends Scope diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index d91122e4fa..5c1f49399e 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -132,8 +132,8 @@ trait DatabasesBase Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $presidents['body']['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ diff --git a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php index 8a3f8d83a5..ca77cf2581 100644 --- a/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Databases; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; diff --git a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php index f91fd4ff26..8484996058 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Database; use Utopia\Database\Helpers\ID; diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index 1c5029d842..7ba6dbd189 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -3,10 +3,10 @@ namespace Tests\E2E\Services\Databases; use Appwrite\Extend\Exception as AppwriteException; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Tests\E2E\Client; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -1665,7 +1665,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('lorem', $attribute['default']); @@ -1807,7 +1807,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('torsten@appwrite.io', $attribute['default']); @@ -1950,7 +1950,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('127.0.0.1', $attribute['default']); @@ -2092,7 +2092,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('http://appwrite.io', $attribute['default']); @@ -2238,7 +2238,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(123, $attribute['default']); @@ -2501,7 +2501,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(123.456, $attribute['default']); @@ -2760,7 +2760,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals(true, $attribute['default']); @@ -2902,7 +2902,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('1975-06-12 14:12:55+02:00', $attribute['default']); @@ -3049,7 +3049,7 @@ class DatabasesCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - $attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null; + $attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null; $this->assertNotNull($attribute); $this->assertFalse($attribute['required']); $this->assertEquals('lorem', $attribute['default']); diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php index b1d197f010..ca8753f374 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsGuestTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php index 8377b9c803..066d83a7ee 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Databases; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index 90252198dc..f72405008d 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Functions; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 71d139a813..1b9edc4f02 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -8,7 +8,6 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; @@ -370,10 +369,10 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-mode' => 'admin', ]; - $variable = $this->client->call(Client::METHOD_POST, '/project/variables', $headers, [ + $variable = $this->client->call(Client::METHOD_POST, '/project/variables', $headers, [ 'key' => 'GLOBAL_VARIABLE', 'value' => 'Global Variable Value', - ]); + ]); $this->assertEquals(201, $variable['headers']['status-code']); diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 7fe7e5cdd3..c17b8a5c24 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -6,9 +6,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Utopia\App; use Utopia\Database\Helpers\ID; -use Utopia\DSN\DSN; class AccountTest extends Scope { diff --git a/tests/e2e/Services/GraphQL/AuthTest.php b/tests/e2e/Services/GraphQL/AuthTest.php index b8689c1442..ecce29f2b3 100644 --- a/tests/e2e/Services/GraphQL/AuthTest.php +++ b/tests/e2e/Services/GraphQL/AuthTest.php @@ -7,8 +7,8 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\Database\Helpers\ID; -use Utopia\Database\Helpers\Role; use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; class AuthTest extends Scope { diff --git a/tests/e2e/Services/GraphQL/BatchTest.php b/tests/e2e/Services/GraphQL/BatchTest.php index 7d154de802..de0534c749 100644 --- a/tests/e2e/Services/GraphQL/BatchTest.php +++ b/tests/e2e/Services/GraphQL/BatchTest.php @@ -77,17 +77,17 @@ class BatchTest extends Scope 'name' => 'Tester 1', ], ], - [ - 'query' => 'mutation CreateTeam($teamId: String! $name: String!) { + [ + 'query' => 'mutation CreateTeam($teamId: String! $name: String!) { teamsCreate(teamId: $teamId, name: $name) { name } }', - 'variables' => [ - 'teamId' => ID::unique(), - 'name' => 'Team 1', - ], - ]]; + 'variables' => [ + 'teamId' => ID::unique(), + 'name' => 'Team 1', + ], + ]]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ 'content-type' => 'application/json', diff --git a/tests/e2e/Services/GraphQL/ScopeTest.php b/tests/e2e/Services/GraphQL/ScopeTest.php index ebf535268e..a270d6e660 100644 --- a/tests/e2e/Services/GraphQL/ScopeTest.php +++ b/tests/e2e/Services/GraphQL/ScopeTest.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\GraphQL; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\SideClient; use Tests\E2E\Scopes\SideServer; use Utopia\Database\Helpers\ID; diff --git a/tests/e2e/Services/Health/HealthBase.php b/tests/e2e/Services/Health/HealthBase.php index cbd0f97668..545cbc893f 100644 --- a/tests/e2e/Services/Health/HealthBase.php +++ b/tests/e2e/Services/Health/HealthBase.php @@ -2,8 +2,6 @@ namespace Tests\E2E\Services\Health; -use Tests\E2E\Client; - trait HealthBase { } diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index dde89a6a71..5fd7ab96da 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -3,9 +3,8 @@ namespace Tests\E2E\Services\Health; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; -use Tests\E2E\Scopes\SideClient; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; class HealthCustomServerTest extends Scope @@ -512,4 +511,52 @@ class HealthCustomServerTest extends Scope return []; } + + public function testUsageSuccess() + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/health/queue/usage', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertIsInt($response['body']['size']); + $this->assertLessThan(100, $response['body']['size']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/health/queue/usage?threshold=0', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + $this->assertEquals(503, $response['headers']['status-code']); + } + + public function testUsageDumpSuccess() + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/health/queue/usage-dump', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertIsInt($response['body']['size']); + $this->assertLessThan(100, $response['body']['size']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/health/queue/usage-dump?threshold=0', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + $this->assertEquals(503, $response['headers']['status-code']); + } } diff --git a/tests/e2e/Services/Locale/LocaleConsoleClientTest.php b/tests/e2e/Services/Locale/LocaleConsoleClientTest.php index 29b3150fed..c72e554df7 100644 --- a/tests/e2e/Services/Locale/LocaleConsoleClientTest.php +++ b/tests/e2e/Services/Locale/LocaleConsoleClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class LocaleConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleCustomClientTest.php b/tests/e2e/Services/Locale/LocaleCustomClientTest.php index b28584280e..6d6108dec1 100644 --- a/tests/e2e/Services/Locale/LocaleCustomClientTest.php +++ b/tests/e2e/Services/Locale/LocaleCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class LocaleCustomClientTest extends Scope diff --git a/tests/e2e/Services/Locale/LocaleCustomServerTest.php b/tests/e2e/Services/Locale/LocaleCustomServerTest.php index 62d4e76802..1513f9b342 100644 --- a/tests/e2e/Services/Locale/LocaleCustomServerTest.php +++ b/tests/e2e/Services/Locale/LocaleCustomServerTest.php @@ -2,7 +2,6 @@ namespace Tests\E2E\Services\Locale; -use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; diff --git a/tests/e2e/Services/Projects/ProjectsBase.php b/tests/e2e/Services/Projects/ProjectsBase.php index a9ccd73900..53d9626252 100644 --- a/tests/e2e/Services/Projects/ProjectsBase.php +++ b/tests/e2e/Services/Projects/ProjectsBase.php @@ -2,8 +2,6 @@ namespace Tests\E2E\Services\Projects; -use Tests\E2E\Client; - trait ProjectsBase { } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index c2a4838625..6f60f01c73 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -4,11 +4,11 @@ namespace Tests\E2E\Services\Projects; use Appwrite\Auth\Auth; use Appwrite\Extend\Exception; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectConsole; -use Tests\E2E\Scopes\SideClient; use Tests\E2E\Client; use Tests\E2E\General\UsageTest; +use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\SideClient; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; @@ -1496,9 +1496,9 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - /** - * Reset - */ + /** + * Reset + */ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1613,9 +1613,9 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); - /** - * Reset - */ + /** + * Reset + */ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/password-history', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Projects/ProjectsCustomClientTest.php b/tests/e2e/Services/Projects/ProjectsCustomClientTest.php index 9dfd48ce50..25140309af 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomClientTest.php @@ -2,10 +2,9 @@ namespace Tests\E2E\Services\Projects; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Tests\E2E\Client; class ProjectsCustomClientTest extends Scope { diff --git a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php index 1c5b48f146..436d1df611 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Projects; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Tests\E2E\Client; class ProjectsCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Realtime/RealtimeBase.php b/tests/e2e/Services/Realtime/RealtimeBase.php index 62bb7f5d3b..30c411ba93 100644 --- a/tests/e2e/Services/Realtime/RealtimeBase.php +++ b/tests/e2e/Services/Realtime/RealtimeBase.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Realtime; -use WebSocket\ConnectionException; use WebSocket\Client as WebSocketClient; +use WebSocket\ConnectionException; trait RealtimeBase { diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index 82068f1301..6ab2874f8e 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Realtime; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\Helpers\ID; diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php index a54a3142e4..9b73566bda 100644 --- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php @@ -4,8 +4,8 @@ namespace Tests\E2E\Services\Realtime; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; use Utopia\CLI\Console; use Utopia\Database\Helpers\ID; diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index b5023a2afd..78548ca1ac 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Storage; use Appwrite\Extend\Exception; use CURLFile; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; diff --git a/tests/e2e/Services/Storage/StorageConsoleClientTest.php b/tests/e2e/Services/Storage/StorageConsoleClientTest.php index e75af0e1a3..5b6731b35e 100644 --- a/tests/e2e/Services/Storage/StorageConsoleClientTest.php +++ b/tests/e2e/Services/Storage/StorageConsoleClientTest.php @@ -3,8 +3,8 @@ namespace Tests\E2E\Services\Storage; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Database\Helpers\ID; diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index 12fc006968..c723fba50a 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -4,10 +4,9 @@ namespace Tests\E2E\Services\Storage; use CURLFile; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -125,18 +124,18 @@ class StorageCustomClientTest extends Scope * Test for SUCCESS */ $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'bucketId' => ID::unique(), - 'name' => 'Test Bucket', - 'permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket', + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], ]); $bucketId = $bucket['body']['$id']; @@ -144,11 +143,11 @@ class StorageCustomClientTest extends Scope $this->assertNotEmpty($bucketId); $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [ - 'content-type' => 'multipart/form-data', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'fileId' => ID::unique(), - 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'), ]); $fileId = $file['body']['$id']; @@ -160,45 +159,45 @@ class StorageCustomClientTest extends Scope $this->assertEquals(47218, $file['body']['sizeOriginal']); $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(200, $file['headers']['status-code']); $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], [ - 'name' => 'permissions.png', + 'name' => 'permissions.png', ]); $this->assertEquals(200, $file['headers']['status-code']); $file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ]); $this->assertEquals(204, $file['headers']['status-code']); diff --git a/tests/e2e/Services/Storage/StorageCustomServerTest.php b/tests/e2e/Services/Storage/StorageCustomServerTest.php index 585f91070c..1dafd8ca06 100644 --- a/tests/e2e/Services/Storage/StorageCustomServerTest.php +++ b/tests/e2e/Services/Storage/StorageCustomServerTest.php @@ -85,8 +85,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -176,8 +176,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/' . $id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -196,8 +196,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/empty', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -209,8 +209,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/id-is-really-long-id-is-really-long-id-is-really-long-id-is-really-long', array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -277,8 +277,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/' . $id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) @@ -291,8 +291,8 @@ class StorageCustomServerTest extends Scope '/storage/buckets/' . $id, array_merge( [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders() ) diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 6b93b01aad..2328e4cdbf 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -3,7 +3,6 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index dff1c85716..03dffac6aa 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -3,7 +3,6 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; @@ -635,9 +634,9 @@ trait TeamsBaseClient return $data; } - /** - * @depends testUpdateTeamMembershipRoles - */ + /** + * @depends testUpdateTeamMembershipRoles + */ public function testDeleteTeamMembership($data): array { $teamUid = $data['teamUid'] ?? ''; diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index e86c18a8e2..61d0f6a027 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -3,10 +3,9 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Utopia\Database\Helpers\ID; class TeamsConsoleClientTest extends Scope { @@ -15,55 +14,6 @@ class TeamsConsoleClientTest extends Scope 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' => ID::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']); - } - /** * @depends testCreateTeam */ @@ -79,10 +29,10 @@ class TeamsConsoleClientTest extends Scope $user = $this->client->call(Client::METHOD_POST, '/account', [ 'content-type' => 'application/json', 'x-appwrite-project' => 'console'], [ - 'userId' => 'unique()', - 'email' => $email, - 'password' => $password, - 'name' => $name, + 'userId' => 'unique()', + 'email' => $email, + 'password' => $password, + 'name' => $name, ], false); $this->assertEquals(201, $user['headers']['status-code']); diff --git a/tests/e2e/Services/Teams/TeamsCustomClientTest.php b/tests/e2e/Services/Teams/TeamsCustomClientTest.php index 3b46cbcb7f..83a8080d1d 100644 --- a/tests/e2e/Services/Teams/TeamsCustomClientTest.php +++ b/tests/e2e/Services/Teams/TeamsCustomClientTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E\Services\Teams; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; class TeamsCustomClientTest extends Scope diff --git a/tests/e2e/Services/Teams/TeamsCustomServerTest.php b/tests/e2e/Services/Teams/TeamsCustomServerTest.php index ccbb598934..325b5892fc 100644 --- a/tests/e2e/Services/Teams/TeamsCustomServerTest.php +++ b/tests/e2e/Services/Teams/TeamsCustomServerTest.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Teams; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; -use Tests\E2E\Client; class TeamsCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 81f6149c96..1737e0483d 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -957,22 +957,22 @@ trait UsersBase /** * Test for SUCCESS */ - $session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [ + $session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], [ + ], [ 'email' => 'users.service@updated.com', 'password' => 'password' - ]); + ]); $this->assertEquals($session['headers']['status-code'], 201); - $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/password', array_merge([ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/password', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ + ], $this->getHeaders()), [ 'password' => '', - ]); + ]); $this->assertEquals($user['headers']['status-code'], 200); $this->assertNotEmpty($user['body']['$id']); diff --git a/tests/e2e/Services/Users/UsersConsoleClientTest.php b/tests/e2e/Services/Users/UsersConsoleClientTest.php index 0f5c4602b2..967104f5db 100644 --- a/tests/e2e/Services/Users/UsersConsoleClientTest.php +++ b/tests/e2e/Services/Users/UsersConsoleClientTest.php @@ -2,9 +2,9 @@ namespace Tests\E2E\Services\Users; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; class UsersConsoleClientTest extends Scope diff --git a/tests/e2e/Services/Users/UsersCustomServerTest.php b/tests/e2e/Services/Users/UsersCustomServerTest.php index 6b9a990d4c..2442f1bf7d 100644 --- a/tests/e2e/Services/Users/UsersCustomServerTest.php +++ b/tests/e2e/Services/Users/UsersCustomServerTest.php @@ -2,7 +2,6 @@ namespace Tests\E2E\Services\Users; -use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; diff --git a/tests/e2e/Services/VCS/VCSConsoleClientTest.php b/tests/e2e/Services/VCS/VCSConsoleClientTest.php index 697fbdba91..5e04c81a86 100644 --- a/tests/e2e/Services/VCS/VCSConsoleClientTest.php +++ b/tests/e2e/Services/VCS/VCSConsoleClientTest.php @@ -2,16 +2,16 @@ namespace Tests\E2E\Services\VCS; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\App; +use Utopia\Cache\Adapter\None; +use Utopia\Cache\Cache; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; use Utopia\VCS\Adapter\Git\GitHub; -use Utopia\Cache\Adapter\None; -use Utopia\Cache\Cache; class VCSConsoleClientTest extends Scope { diff --git a/tests/e2e/Services/VCS/VCSCustomClientTest.php b/tests/e2e/Services/VCS/VCSCustomClientTest.php index 084255cd69..26ccc45990 100644 --- a/tests/e2e/Services/VCS/VCSCustomClientTest.php +++ b/tests/e2e/Services/VCS/VCSCustomClientTest.php @@ -2,10 +2,10 @@ namespace Tests\E2E\Services\VCS; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; -use Tests\E2E\Scopes\SideClient; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\SideClient; class VCSCustomClientTest extends Scope { diff --git a/tests/e2e/Services/VCS/VCSCustomServerTest.php b/tests/e2e/Services/VCS/VCSCustomServerTest.php index dee4cd7ced..337acb373b 100644 --- a/tests/e2e/Services/VCS/VCSCustomServerTest.php +++ b/tests/e2e/Services/VCS/VCSCustomServerTest.php @@ -2,10 +2,10 @@ namespace Tests\E2E\Services\VCS; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\ProjectCustom; -use Tests\E2E\Scopes\SideServer; use Tests\E2E\Client; +use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; +use Tests\E2E\Scopes\SideServer; class VCSCustomServerTest extends Scope { diff --git a/tests/e2e/Services/Webhooks/WebhooksBase.php b/tests/e2e/Services/Webhooks/WebhooksBase.php index eff6cbc6a5..d9eb7e46ca 100644 --- a/tests/e2e/Services/Webhooks/WebhooksBase.php +++ b/tests/e2e/Services/Webhooks/WebhooksBase.php @@ -5,7 +5,6 @@ namespace Tests\E2E\Services\Webhooks; use Appwrite\Tests\Retry; use CURLFile; use Tests\E2E\Client; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -27,19 +26,19 @@ trait WebhooksBase * Create database */ $database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'databaseId' => ID::unique(), - 'name' => 'Actors DB', + 'databaseId' => ID::unique(), + 'name' => 'Actors DB', ]); $databaseId = $database['body']['$id']; - /** - * Test for SUCCESS - */ + /** + * Test for SUCCESS + */ $actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php index 2f0d8e465e..f331db905b 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php @@ -4,10 +4,9 @@ namespace Tests\E2E\Services\Webhooks; use Appwrite\Tests\Retry; use Tests\E2E\Client; -use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; +use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Datetime as DatetimeValidator; diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 7f8031ce94..d31c981a03 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -8,7 +8,6 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use Utopia\CLI\Console; -use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; diff --git a/tests/extensions/TestHook.php b/tests/extensions/TestHook.php index 67c1215c4c..507296acb9 100644 --- a/tests/extensions/TestHook.php +++ b/tests/extensions/TestHook.php @@ -3,7 +3,6 @@ namespace Appwrite\Tests; use PHPUnit\Runner\AfterTestHook; -use Exception; class TestHook implements AfterTestHook { diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php index ea6e9dc6c1..705da42879 100644 --- a/tests/unit/Auth/AuthTest.php +++ b/tests/unit/Auth/AuthTest.php @@ -3,12 +3,12 @@ namespace Tests\Unit\Auth; use Appwrite\Auth\Auth; +use PHPUnit\Framework\TestCase; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; -use PHPUnit\Framework\TestCase; use Utopia\Database\Validator\Roles; class AuthTest extends TestCase diff --git a/tests/unit/Auth/Validator/PasswordDictionaryTest.php b/tests/unit/Auth/Validator/PasswordDictionaryTest.php index 5c8d47923c..60b5ca7ae3 100644 --- a/tests/unit/Auth/Validator/PasswordDictionaryTest.php +++ b/tests/unit/Auth/Validator/PasswordDictionaryTest.php @@ -4,7 +4,6 @@ namespace Tests\Unit\Auth\Validator; use Appwrite\Auth\Validator\PasswordDictionary; use PHPUnit\Framework\TestCase; -use Utopia\Database\Document; class PasswordDictionaryTest extends TestCase { diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php index 6fe7dda71f..8ba0374093 100644 --- a/tests/unit/Messaging/MessagingChannelsTest.php +++ b/tests/unit/Messaging/MessagingChannelsTest.php @@ -3,9 +3,9 @@ namespace Tests\Unit\Messaging; use Appwrite\Auth\Auth; -use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; diff --git a/tests/unit/Messaging/MessagingTest.php b/tests/unit/Messaging/MessagingTest.php index c2e3971945..c2b6490869 100644 --- a/tests/unit/Messaging/MessagingTest.php +++ b/tests/unit/Messaging/MessagingTest.php @@ -2,9 +2,9 @@ namespace Tests\Unit\Messaging; -use Utopia\Database\Document; use Appwrite\Messaging\Adapter\Realtime; use PHPUnit\Framework\TestCase; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; diff --git a/tests/unit/Usage/StatsTest.php b/tests/unit/Usage/StatsTest.php index 794caebdf5..c564b31c92 100644 --- a/tests/unit/Usage/StatsTest.php +++ b/tests/unit/Usage/StatsTest.php @@ -20,12 +20,12 @@ class StatsTest extends TestCase public function setUp(): void { $env = App::getEnv('_APP_CONNECTIONS_QUEUE', AppwriteURL::unparse([ - 'scheme' => 'redis', - 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), - 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), - 'user' => App::getEnv('_APP_REDIS_USER', ''), - 'pass' => App::getEnv('_APP_REDIS_PASS', ''), - ])); + 'scheme' => 'redis', + 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), + 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), + 'user' => App::getEnv('_APP_REDIS_USER', ''), + 'pass' => App::getEnv('_APP_REDIS_PASS', ''), + ])); $dsn = explode('=', $env); $dsn = count($dsn) > 1 ? $dsn[1] : $dsn[0]; diff --git a/tests/unit/Utopia/Request/Filters/First.php b/tests/unit/Utopia/Request/Filters/First.php new file mode 100644 index 0000000000..7e00abfc57 --- /dev/null +++ b/tests/unit/Utopia/Request/Filters/First.php @@ -0,0 +1,19 @@ +filter = new V15(); - } - - public function tearDown(): void - { - } - - public function limitOffsetProvider(): array - { - return [ - 'basic test' => [ - ['limit' => '12', 'offset' => '0'], - ['queries' => ['limit(12)', 'offset(0)']] - ], - ]; - } - - /** - * @dataProvider limitOffsetProvider - */ - public function testListAccountLogs(array $content, array $expected): void - { - $model = 'account.listLogs'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function testGetAccountInitials(): void - { - $model = 'account.initials'; - - $content = ['color' => 'deadbeef']; - $expected = []; - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function limitOffsetCursorOrderTypeProvider(): array - { - return [ - 'basic test' => [ - [ - 'limit' => '12', - 'offset' => '0', - 'cursor' => 'abcd', - 'cursorDirection' => 'before', - 'orderType' => 'asc', - ], - [ - 'queries' => [ - 'limit(12)', - 'offset(0)', - 'cursorBefore("abcd")', - 'orderAsc("")' - ] - ], - ], - ]; - } - - public function cursorProvider(): array - { - return [ - 'cursorDirection after' => [ - [ - 'cursor' => 'abcd', - 'cursorDirection' => 'after', - ], - [ - 'queries' => [ - 'cursorAfter("abcd")', - ] - ], - ], - 'cursorDirection invalid' => [ - [ - 'cursor' => 'abcd', - 'cursorDirection' => 'invalid', - ], - [ - 'queries' => [ - 'cursorAfter("abcd")', - ] - ], - ], - ]; - } - - public function orderTypeProvider(): array - { - return [ - 'orderType desc' => [ - [ - 'orderType' => 'DESC', - ], - [ - 'queries' => [ - 'orderDesc("")', - ] - ], - ], - 'orderType invalid' => [ - [ - 'orderType' => 'invalid', - ], - [ - 'queries' => [ - 'orderAsc("")', - ] - ], - ], - ]; - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListDatabases(array $content, array $expected): void - { - $model = 'databases.list'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetProvider - */ - public function testListDatabaseLogs(array $content, array $expected): void - { - $model = 'databases.listLogs'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function collectionPermissionProvider(): array - { - return [ - 'permission collection' => [ - ['permission' => 'collection'], - ['documentSecurity' => false], - ], - 'permission document' => [ - ['permission' => 'document'], - ['documentSecurity' => true], - ], - 'permission empty' => [ - [], - [], - ], - 'permission invalid' => [ - ['permission' => 'invalid'], - ['documentSecurity' => false], - ], - ]; - } - - public function readWriteProvider(): array - { - return [ - 'read all types' => [ - [ - 'read' => [ - 'role:all', - 'role:guest', - 'role:member', - 'user:a', - 'team:b', - 'team:c/member', - 'member:z', - ], - ], - [ - 'permissions' => [ - 'read("any")', - 'read("guests")', - 'read("users")', - 'read("user:a")', - 'read("team:b")', - 'read("team:c/member")', - 'read("member:z")', - ], - ], - ], - 'read invalid' => [ - ['read' => ['invalid', 'invalid:a']], - ['permissions' => ['read("invalid:a")']], - ], - 'write all types' => [ - [ - 'write' => [ - 'role:all', - 'role:guest', - 'role:member', - 'user:a', - 'team:b', - 'team:c/member', - 'member:z', - ], - ], - [ - 'permissions' => [ - 'write("users")', - 'write("users")', - 'write("user:a")', - 'write("team:b")', - 'write("team:c/member")', - 'write("member:z")', - ], - ], - ], - 'write invalid' => [ - ['write' => ['invalid', 'invalid:a']], - ['permissions' => ['write("invalid:a")']], - ] - ]; - } - - /** - * @dataProvider collectionPermissionProvider - * @dataProvider readWriteProvider - */ - public function testCreateCollection(array $content, array $expected): void - { - $model = 'databases.createCollection'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListCollections(array $content, array $expected): void - { - $model = 'databases.listCollections'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetProvider - */ - public function testListCollectionLogs(array $content, array $expected): void - { - $model = 'databases.listCollectionLogs'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider collectionPermissionProvider - * @dataProvider readWriteProvider - */ - public function testUpdateCollection(array $content, array $expected): void - { - $model = 'databases.updateCollection'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider readWriteProvider - */ - public function testCreateDocument(array $content, array $expected): void - { - $model = 'databases.createDocument'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function ordersProvider(): array - { - return [ - 'basic test' => [ - [ - 'orderAttributes' => ['lastName', 'firstName'], - 'orderTypes' => ['DESC', 'ASC'], - ], - [ - 'queries' => [ - 'orderDesc("lastName")', - 'orderAsc("firstName")', - ] - ], - ], - 'orderType only' => [ - [ - 'orderTypes' => ['DESC'], - ], - [ - 'queries' => [ - 'orderDesc("")', - ] - ], - ], - 'orderType invalid' => [ - [ - 'orderAttributes' => ['lastName'], - 'orderTypes' => ['invalid'], - ], - [ - 'queries' => [ - 'orderAsc("lastName")', - ] - ], - ], - ]; - } - - public function filtersProvider(): array - { - return [ - 'all filters' => [ - [ - 'queries' => [ - 'lastName.equal("Smith", "Jackson")', - 'firstName.notEqual("John")', - 'age.lesser(50)', - 'age.lesserEqual(51)', - 'age.greater(20)', - 'age.greaterEqual(21)', - 'address.search("pla")', - ], - ], - [ - 'queries' => [ - 'equal("lastName", ["Smith", "Jackson"])', - 'notEqual("firstName", ["John"])', - 'lessThan("age", [50])', - 'lessThanEqual("age", [51])', - 'greaterThan("age", [20])', - 'greaterThanEqual("age", [21])', - 'search("address", ["pla"])', - ] - ], - ], - ]; - } - - /** - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider ordersProvider - * @dataProvider filtersProvider - */ - public function testListDocuments(array $content, array $expected): void - { - $model = 'databases.listDocuments'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetProvider - */ - public function testListDocumentLogs(array $content, array $expected): void - { - $model = 'databases.listDocumentLogs'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider readWriteProvider - */ - public function testUpdateDocument(array $content, array $expected): void - { - $model = 'databases.updateDocument'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function executeProvider(): array - { - return [ - 'all roles' => [ - [ - 'execute' => [ - 'role:all', - 'role:guest', - 'role:member', - 'user:a', - 'team:b', - 'team:c/member', - 'member:z', - ], - ], - [ - 'execute' => [ - 'users', - 'users', - 'user:a', - 'team:b', - 'team:c/member', - 'member:z', - ] - ], - ], - ]; - } - - /** - * @dataProvider executeProvider - */ - public function testCreateFunction(array $content, array $expected): void - { - $model = 'functions.create'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListFunctions(array $content, array $expected): void - { - $model = 'functions.list'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider executeProvider - */ - public function testUpdateFunction(array $content, array $expected): void - { - $model = 'functions.update'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListDeployments(array $content, array $expected): void - { - $model = 'functions.listDeployments'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - */ - public function testListExecutions(array $content, array $expected): void - { - $model = 'functions.listExecutions'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListProjects(array $content, array $expected): void - { - $model = 'projects.list'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function expireProvider(): array - { - return [ - 'empty' => [ - [], - [], - ], - 'zero' => [ - ['expire' => '0'], - ['expire' => null], - ], - 'value' => [ - ['expire' => '1602743880'], - ['expire' => Model::TYPE_DATETIME_EXAMPLE], - ], - ]; - } - - /** - * @dataProvider expireProvider - */ - public function testCreateKey(array $content, array $expected) - { - $model = 'projects.createKey'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider expireProvider - */ - public function testUpdateKey(array $content, array $expected) - { - $model = 'projects.updateKey'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function bucketPermissionProvider(): array - { - return [ - 'permission bucket' => [ - ['permission' => 'bucket'], - ['fileSecurity' => false], - ], - 'permission document' => [ - ['permission' => 'file'], - ['fileSecurity' => true], - ], - 'permission empty' => [ - [], - [], - ], - 'permission invalid' => [ - ['permission' => 'invalid'], - ['fileSecurity' => false], - ], - ]; - } - - /** - * @dataProvider bucketPermissionProvider - * @dataProvider readWriteProvider - */ - public function testCreateBucket(array $content, array $expected) - { - $model = 'storage.createBucket'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListBuckets(array $content, array $expected): void - { - $model = 'storage.listBuckets'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider bucketPermissionProvider - * @dataProvider readWriteProvider - */ - public function testUpdateBucket(array $content, array $expected) - { - $model = 'storage.updateBucket'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider readWriteProvider - */ - public function testCreateFile(array $content, array $expected) - { - $model = 'storage.createFile'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListFiles(array $content, array $expected): void - { - $model = 'storage.listFiles'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider readWriteProvider - */ - public function testUpdateFile(array $content, array $expected) - { - $model = 'storage.updateFile'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListTeams(array $content, array $expected): void - { - $model = 'teams.list'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListTeamMemberships(array $content, array $expected): void - { - $model = 'teams.listMemberships'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetProvider - */ - public function testListTeamLogs(array $content, array $expected): void - { - $model = 'teams.listLogs'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetCursorOrderTypeProvider - * @dataProvider limitOffsetProvider - * @dataProvider cursorProvider - * @dataProvider orderTypeProvider - */ - public function testListUsers(array $content, array $expected): void - { - $model = 'users.list'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider limitOffsetProvider - */ - public function testListUserLogs(array $content, array $expected): void - { - $model = 'users.listLogs'; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } -} diff --git a/tests/unit/Utopia/Request/Filters/V16Test.php b/tests/unit/Utopia/Request/Filters/V16Test.php index daa1d45a0d..322e24260a 100644 --- a/tests/unit/Utopia/Request/Filters/V16Test.php +++ b/tests/unit/Utopia/Request/Filters/V16Test.php @@ -4,7 +4,6 @@ namespace Tests\Unit\Utopia\Request\Filters; use Appwrite\Utopia\Request\Filter; use Appwrite\Utopia\Request\Filters\V16; -use Appwrite\Utopia\Response\Model; use PHPUnit\Framework\TestCase; class V16Test extends TestCase diff --git a/tests/unit/Utopia/Request/Filters/V17Test.php b/tests/unit/Utopia/Request/Filters/V17Test.php index 4c0e155ec5..3efa72c77a 100644 --- a/tests/unit/Utopia/Request/Filters/V17Test.php +++ b/tests/unit/Utopia/Request/Filters/V17Test.php @@ -72,7 +72,7 @@ class V17Test extends TestCase ] ], ] - ]; + ]; } /** diff --git a/tests/unit/Utopia/RequestTest.php b/tests/unit/Utopia/RequestTest.php new file mode 100644 index 0000000000..73daaa88bc --- /dev/null +++ b/tests/unit/Utopia/RequestTest.php @@ -0,0 +1,53 @@ +request = new Request(new SwooleRequest()); + } + + public function testFilters(): void + { + $this->assertFalse($this->request->hasFilters()); + $this->assertIsArray($this->request->getFilters()); + $this->assertEmpty($this->request->getFilters()); + + $this->request->addFilter(new First()); + $this->request->addFilter(new Second()); + + $this->assertTrue($this->request->hasFilters()); + $this->assertCount(2, $this->request->getFilters()); + + $route = new Route(Request::METHOD_GET, '/test'); + $route->label('sdk.method', 'method'); + $route->label('sdk.namespace', 'namespace'); + // set test header to prevent header populaten inside the request class + $this->request->addHeader('EXAMPLE', 'VALUE'); + $this->request->setRoute($route); + $this->request->setQueryString([ + 'initial' => true, + 'first' => false + ]); + $output = $this->request->getParams(); + + $this->assertArrayHasKey('initial', $output); + $this->assertTrue($output['initial']); + $this->assertArrayHasKey('first', $output); + $this->assertTrue($output['first']); + $this->assertArrayHasKey('second', $output); + $this->assertTrue($output['second']); + $this->assertArrayNotHasKey('deleted', $output); + } +} diff --git a/tests/unit/Utopia/Response/Filters/First.php b/tests/unit/Utopia/Response/Filters/First.php new file mode 100644 index 0000000000..bf29b4f613 --- /dev/null +++ b/tests/unit/Utopia/Response/Filters/First.php @@ -0,0 +1,19 @@ +filter = new V15(); - } - - public function tearDown(): void - { - } - - public function createdAtUpdatedAtProvider(): array - { - return [ - 'basic datetimes' => [ - [ - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - ], - [ - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - ], - ], - 'null datetime' => [ - [ - '$createdAt' => null, - '$updatedAt' => null, - ], - [ - '$createdAt' => 0, - '$updatedAt' => 0, - ], - ], - 'empty datetime' => [ - [ - '$createdAt' => '', - '$updatedAt' => '', - ], - [ - '$createdAt' => 0, - '$updatedAt' => 0, - ], - ], - ]; - } - - public function permissionsProvider(): array - { - return [ - 'basic permissions' => [ - [ - '$permissions' => [ - Permission::read(Role::any()), - Permission::write(Role::user('608f9da25e7e1')), - ], - ], - [ - '$read' => ['role:all'], - '$write' => ['user:608f9da25e7e1'], - ], - ], - 'all roles' => [ - [ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::guests()), - Permission::read(Role::users()), - Permission::read(Role::user('asdf')), - Permission::read(Role::team('qwer')), - Permission::read(Role::team('qwer', 'uiop')), - Permission::read(Role::member('zxcv')), - ], - ], - [ - '$read' => [ - 'role:all', - 'role:guest', - 'role:member', - 'user:asdf', - 'team:qwer', - 'team:qwer/uiop', - 'member:zxcv', - ], - '$write' => [], - ], - ], - 'create conversion' => [ - [ - '$permissions' => [Permission::create(Role::user('a'))], - ], - [ - '$read' => [], - '$write' => ['user:a'], - ], - ], - 'update conversion' => [ - [ - '$permissions' => [Permission::update(Role::user('a'))], - ], - [ - '$read' => [], - '$write' => ['user:a'], - ], - ], - 'delete conversion' => [ - [ - '$permissions' => [Permission::delete(Role::user('a'))], - ], - [ - '$read' => [], - '$write' => ['user:a'], - ], - ], - 'write conversion' => [ - [ - '$permissions' => [Permission::write(Role::user('a'))], - ], - [ - '$read' => [], - '$write' => ['user:a'], - ], - ], - ]; - } - - public function testAccount(): void - { - $model = Response::MODEL_ACCOUNT; - - $content = [ - '$id' => '6264711f995c5b012b48', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - 'name' => 'John Doe', - 'registration' => '2020-06-24T06:47:30.000Z', - 'status' => true, - 'passwordUpdate' => '2020-06-24T06:47:30.000Z', - 'email' => 'john@appwrite.io', - 'phone' => '+4930901820', - 'emailVerification' => true, - 'phoneVerification' => true, - 'prefs' => new \stdClass(), - ]; - - $expected = [ - '$id' => '6264711f995c5b012b48', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - 'name' => 'John Doe', - 'registration' => 1592981250, - 'status' => true, - 'passwordUpdate' => 1592981250, - 'email' => 'john@appwrite.io', - 'phone' => '+4930901820', - 'emailVerification' => true, - 'phoneVerification' => true, - 'prefs' => new \stdClass(), - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function bucketProvider(): array - { - return [ - 'basic bucket' => [ - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - 'fileSecurity' => true, - '$permissions' => [ - Permission::read(Role::any()), - Permission::write(Role::user('608f9da25e7e1')), - ], - 'name' => 'Documents', - 'enabled' => false, - 'maximumFileSize' => 100, - 'allowedFileExtensions' => [ - 'jpg', - 'png' - ], - 'encryption' => false, - 'antivirus' => false, - ], - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - '$read' => ['role:all'], - '$write' => ['user:608f9da25e7e1'], - 'permission' => 'file', - 'name' => 'Documents', - 'enabled' => false, - 'maximumFileSize' => 100, - 'allowedFileExtensions' => [ - 'jpg', - 'png' - ], - 'encryption' => false, - 'antivirus' => false, - ], - ], - 'false fileSecurity' => [ - ['fileSecurity' => false], - ['permission' => 'bucket'], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - * @dataProvider bucketProvider - */ - public function testBucket(array $content, array $expected): void - { - $model = Response::MODEL_BUCKET; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - * @dataProvider bucketProvider - */ - public function testBucketList(array $content, array $expected): void - { - $model = Response::MODEL_BUCKET_LIST; - - $content = [ - 'buckets' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'buckets' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function buildProvider(): array - { - return [ - 'build start and end time' => [ - [ - 'startTime' => '2020-06-24T06:47:30.000Z', - 'endTime' => '2020-06-24T06:47:30.000Z', - ], - [ - 'startTime' => 1592981250, - 'endTime' => 1592981250, - ] - ] - ]; - } - - /** - * @dataProvider buildProvider - */ - public function testBuild(): void - { - $model = Response::MODEL_BUILD; - - $content = [ - 'startTime' => '2020-06-24T06:47:30.000Z', - 'endTime' => '2020-06-24T06:47:30.000Z', - ]; - - $expected = [ - 'startTime' => 1592981250, - 'endTime' => 1592981250, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider buildProvider - */ - public function testBuildList(array $content, array $expected): void - { - $model = Response::MODEL_BUILD_LIST; - - $content = [ - 'builds' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'builds' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function collectionProvider(): array - { - return [ - 'basic collection' => [ - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - '$permissions' => [ - Permission::read(Role::any()), - Permission::write(Role::user('608f9da25e7e1')), - ], - 'documentSecurity' => true, - 'databaseId' => '5e5ea5c16897e', - 'name' => 'My Collection', - 'enabled' => false, - 'attributes' => [ - 'key' => 'isEnabled', - 'type' => 'boolean', - 'status' => 'available', - 'required' => true, - 'array' => false, - 'default' => false - ], - 'indexes' => [ - 'key' => 'index1', - 'type' => 'primary', - 'status' => 'available', - 'attributes' => [], - 'orders' => [] - ], - ], - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - '$read' => [ - 'role:all' - ], - '$write' => [ - 'user:608f9da25e7e1' - ], - 'databaseId' => '5e5ea5c16897e', - 'name' => 'My Collection', - 'enabled' => false, - 'permission' => 'document', - 'attributes' => [ - 'key' => 'isEnabled', - 'type' => 'boolean', - 'status' => 'available', - 'required' => true, - 'array' => false, - 'default' => false - ], - 'indexes' => [ - 'key' => 'index1', - 'type' => 'primary', - 'status' => 'available', - 'attributes' => [], - 'orders' => [] - ], - ], - ], - 'false documentSecurity' => [ - ['documentSecurity' => false], - ['permission' => 'collection'], - ], - - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - * @dataProvider collectionProvider - */ - public function testCollection(array $content, array $expected): void - { - $model = Response::MODEL_COLLECTION; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - * @dataProvider collectionProvider - */ - public function testCollectionList(array $content, array $expected): void - { - $model = Response::MODEL_COLLECTION_LIST; - - $content = [ - 'collections' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'collections' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testDatabase(array $content, array $expected): void - { - $model = Response::MODEL_DATABASE; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testDatabaseList(array $content, array $expected): void - { - $model = Response::MODEL_DATABASE_LIST; - - $content = [ - 'databases' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'databases' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testDeployment(array $content, array $expected): void - { - $model = Response::MODEL_DEPLOYMENT; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testDeploymentList(array $content, array $expected): void - { - $model = Response::MODEL_DEPLOYMENT_LIST; - - $content = [ - 'deployments' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'deployments' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function documentProvider(): array - { - return [ - 'basic document' => [ - [ - '$id' => '5e5ea5c16897e', - '$collectionId' => '5e5ea5c15117e', - '$databaseId' => '5e5ea5c15117e', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - '$permissions' => [Permission::read(Role::any())] - ], - [ - '$id' => '5e5ea5c16897e', - '$collection' => '5e5ea5c15117e', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - '$read' => ['role:all'], - '$write' => [], - ], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - * @dataProvider documentProvider - */ - public function testDocument(array $content, array $expected): void - { - $model = Response::MODEL_DOCUMENT; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - */ - public function testDocumentList(array $content, array $expected): void - { - $model = Response::MODEL_DOCUMENT_LIST; - - $content = [ - 'documents' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'documents' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testDomain(array $content, array $expected): void - { - $model = Response::MODEL_DOMAIN; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testDomainList(array $content, array $expected): void - { - $model = Response::MODEL_DOMAIN_LIST; - - $content = [ - 'domains' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'domains' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function executionProvider(): array - { - return [ - 'basic execution' => [ - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - '$permissions' => [ - "any" - ], - 'functionId' => '5e5ea6g16897e', - 'trigger' => 'http', - 'status' => 'processing', - 'statusCode' => 0, - 'response' => '', - 'stdout' => '', - 'stderr' => '', - 'duration' => 0.4 - ], - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - '$read' => [ - "role:all" - ], - 'functionId' => '5e5ea6g16897e', - 'trigger' => 'http', - 'status' => 'processing', - 'statusCode' => 0, - 'response' => '', - 'stderr' => '', - 'time' => 0.4 - ], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider executionProvider - */ - public function testExecution(array $content, array $expected): void - { - $model = Response::MODEL_EXECUTION; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider executionProvider - */ - public function testExecutionList(array $content, array $expected): void - { - $model = Response::MODEL_EXECUTION_LIST; - - $content = [ - 'executions' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'executions' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - */ - public function testFile(array $content, array $expected): void - { - $model = Response::MODEL_FILE; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider - */ - public function testFileList(array $content, array $expected): void - { - $model = Response::MODEL_FILE_LIST; - - $content = [ - 'files' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'files' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function functionProvider(): array - { - return [ - 'basic function' => [ - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - 'execute' => [ - Role::users()->toString(), - ], - 'name' => 'My Function', - 'enabled' => true, - 'runtime' => 'python-3.8', - 'deployment' => '5e5ea5c16897e', - 'vars' => [ - [ - '$id' => '631bd31717e034f14aa8', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - 'key' => 'key', - 'value' => 'value', - 'functionId' => '5e5ea5c16897e', - ] - ], - 'events' => [ - 'account.create' - ], - 'schedule' => '5 4 * * *', - 'scheduleNext' => '2020-06-24T06:48:12.000Z', - 'schedulePrevious' => '2020-06-24T06:47:17.000Z', - 'timeout' => 1592981237 - ], - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - 'execute' => [ - 'role:member' - ], - 'name' => 'My Function', - 'status' => 'enabled', - 'runtime' => 'python-3.8', - 'deployment' => '5e5ea5c16897e', - 'vars' => [ - 'key' => 'value' - ], - 'events' => [ - 'account.create' - ], - 'schedule' => '5 4 * * *', - 'scheduleNext' => 1592981292, - 'schedulePrevious' => 1592981237, - 'timeout' => 1592981237 - ], - ], - 'enabled false' => [ - ['enabled' => false], - ['status' => 'disabled'], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider functionProvider - */ - public function testFunc(array $content, array $expected): void - { - $model = Response::MODEL_FUNCTION; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider functionProvider - */ - public function testFuncList(array $content, array $expected): void - { - $model = Response::MODEL_FUNCTION_LIST; - - $content = [ - 'functions' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'functions' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function keyProvider(): array - { - return [ - 'basic key' => [ - ['expire' => '2020-06-24T06:47:30.000Z'], - ['expire' => 1592981250], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider keyProvider - */ - public function testKey(array $content, array $expected): void - { - $model = Response::MODEL_KEY; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider keyProvider - */ - public function testKeyList(array $content, array $expected): void - { - $model = Response::MODEL_KEY_LIST; - - $content = [ - 'keys' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'keys' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function logProvider(): array - { - return [ - 'basic log' => [ - [ - 'event' => 'account.sessions.create', - 'userId' => '610fc2f985ee0', - 'userEmail' => 'john@appwrite.io', - 'userName' => 'John Doe', - 'mode' => 'admin', - 'ip' => '127.0.0.1', - 'time' => '2020-06-24T06:47:30.000Z', - 'osCode' => 'Mac', - 'osName' => 'Mac', - 'osVersion' => 'Mac', - 'clientType' => 'browser', - 'clientCode' => 'CM', - 'clientName' => 'Chrome Mobile iOS', - 'clientVersion' => '84.0', - 'clientEngine' => 'WebKit', - 'clientEngineVersion' => '605.1.15', - 'deviceName' => 'smartphone', - 'deviceBrand' => 'Google', - 'deviceModel' => 'Nexus 5', - 'countryCode' => 'US', - 'countryName' => 'United States' - ], - [ - 'event' => 'account.sessions.create', - 'userId' => '610fc2f985ee0', - 'userEmail' => 'john@appwrite.io', - 'userName' => 'John Doe', - 'mode' => 'admin', - 'ip' => '127.0.0.1', - 'time' => 1592981250, - 'osCode' => 'Mac', - 'osName' => 'Mac', - 'osVersion' => 'Mac', - 'clientType' => 'browser', - 'clientCode' => 'CM', - 'clientName' => 'Chrome Mobile iOS', - 'clientVersion' => '84.0', - 'clientEngine' => 'WebKit', - 'clientEngineVersion' => '605.1.15', - 'deviceName' => 'smartphone', - 'deviceBrand' => 'Google', - 'deviceModel' => 'Nexus 5', - 'countryCode' => 'US', - 'countryName' => 'United States' - ] - ], - ]; - } - - /** - * @dataProvider logProvider - */ - public function testLog(array $content, array $expected): void - { - $model = Response::MODEL_LOG; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider logProvider - */ - public function testLogList(array $content, array $expected): void - { - $model = Response::MODEL_LOG_LIST; - - $content = [ - 'logs' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'logs' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function membershipProvider(): array - { - return [ - 'basic membership' => [ - [ - 'invited' => '2020-06-24T06:47:30.000Z', - 'joined' => '2020-06-24T06:47:30.000Z', - ], - [ - 'invited' => 1592981250, - 'joined' => 1592981250, - ], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider membershipProvider - */ - public function testMembership(array $content, array $expected): void - { - $model = Response::MODEL_MEMBERSHIP; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider membershipProvider - */ - public function testMembershipList(array $content, array $expected): void - { - $model = Response::MODEL_MEMBERSHIP_LIST; - - $content = [ - 'memberships' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'memberships' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function metricProvider(): array - { - return [ - 'basic metric' => [ - [ - 'date' => '2020-06-24T06:47:30.000Z', - ], - [ - 'date' => 1592981250, - ], - ], - ]; - } - - /** - * @dataProvider metricProvider - */ - public function testMetric(array $content, array $expected): void - { - $model = Response::MODEL_METRIC; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testPlatform(array $content, array $expected): void - { - $model = Response::MODEL_PLATFORM; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testPlatformList(array $content, array $expected): void - { - $model = Response::MODEL_PLATFORM_LIST; - - $content = [ - 'platforms' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'platforms' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testProject(array $content, array $expected): void - { - $model = Response::MODEL_PROJECT; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testProjectList(array $content, array $expected): void - { - $model = Response::MODEL_PROJECT_LIST; - - $content = [ - 'projects' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'projects' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function sessionProvider(): array - { - return [ - 'basic session' => [ - [ - '$createdAt' => '2020-06-24T06:47:30.000Z', - 'expire' => '2020-06-24T06:47:30.000Z', - 'providerAccessTokenExpiry' => '2020-06-24T06:47:30.000Z', - ], - [ - '$createdAt' => 1592981250, - 'expire' => 1592981250, - 'providerAccessTokenExpiry' => 1592981250, - ], - ], - 'empty values' => [ - [ - 'providerAccessTokenExpiry' => '', - ], - [ - 'providerAccessTokenExpiry' => 0, - ], - ], - ]; - } - - /** - * @dataProvider sessionProvider - */ - public function testSession(array $content, array $expected): void - { - $model = Response::MODEL_SESSION; - - $result = $this->filter->parse($content, $model); - - $this->assertSame($expected, $result); - } - - /** - * @dataProvider sessionProvider - */ - public function testSessionList(array $content, array $expected): void - { - $model = Response::MODEL_SESSION_LIST; - - $content = [ - 'sessions' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'sessions' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testTeam(array $content, array $expected): void - { - $model = Response::MODEL_TEAM; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testTeamList(array $content, array $expected): void - { - $model = Response::MODEL_TEAM_LIST; - - $content = [ - 'teams' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'teams' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function tokenProvider(): array - { - return [ - 'basic token' => [ - [ - '$createdAt' => '2020-06-24T06:47:30.000Z', - 'expire' => '2020-06-24T06:47:30.000Z', - ], - [ - '$createdAt' => 1592981250, - 'expire' => 1592981250, - ], - ], - ]; - } - - /** - * @dataProvider tokenProvider - */ - public function testToken(array $content, array $expected): void - { - $model = Response::MODEL_TOKEN; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageDatabasesProvider(): array - { - return [ - 'basic usage databases' => [ - [ - 'databasesCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'databasesCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'databasesRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'databasesUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'databasesDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'databasesCount' => [ - ['date' => 1592981250], - ], - 'documentsCount' => [ - ['date' => 1592981250], - ], - 'collectionsCount' => [ - ['date' => 1592981250], - ], - 'databasesCreate' => [ - ['date' => 1592981250], - ], - 'databasesRead' => [ - ['date' => 1592981250], - ], - 'databasesUpdate' => [ - ['date' => 1592981250], - ], - 'databasesDelete' => [ - ['date' => 1592981250], - ], - 'documentsCreate' => [ - ['date' => 1592981250], - ], - 'documentsRead' => [ - ['date' => 1592981250], - ], - 'documentsUpdate' => [ - ['date' => 1592981250], - ], - 'documentsDelete' => [ - ['date' => 1592981250], - ], - 'collectionsCreate' => [ - ['date' => 1592981250], - ], - 'collectionsRead' => [ - ['date' => 1592981250], - ], - 'collectionsUpdate' => [ - ['date' => 1592981250], - ], - 'collectionsDelete' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageDatabasesProvider - */ - public function testUsageDatabases(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_DATABASES; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageDatabaseProvider(): array - { - return [ - 'basic usage database' => [ - [ - 'documentsCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'collectionsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'documentsCount' => [ - ['date' => 1592981250], - ], - 'collectionsCount' => [ - ['date' => 1592981250], - ], - 'documentsCreate' => [ - ['date' => 1592981250], - ], - 'documentsRead' => [ - ['date' => 1592981250], - ], - 'documentsUpdate' => [ - ['date' => 1592981250], - ], - 'documentsDelete' => [ - ['date' => 1592981250], - ], - 'collectionsCreate' => [ - ['date' => 1592981250], - ], - 'collectionsRead' => [ - ['date' => 1592981250], - ], - 'collectionsUpdate' => [ - ['date' => 1592981250], - ], - 'collectionsDelete' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageDatabaseProvider - */ - public function testUsageDatabase(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_DATABASE; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageCollectionProvider(): array - { - return [ - 'basic usage collection' => [ - [ - 'documentsCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documentsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'documentsCount' => [ - ['date' => 1592981250], - ], - 'documentsCreate' => [ - ['date' => 1592981250], - ], - 'documentsRead' => [ - ['date' => 1592981250], - ], - 'documentsUpdate' => [ - ['date' => 1592981250], - ], - 'documentsDelete' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageCollectionProvider - */ - public function testUsageCollection(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_COLLECTION; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageUsersProvider(): array - { - return [ - 'basic usage users' => [ - [ - 'usersCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'usersCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'usersRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'usersUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'usersDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'sessionsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'sessionsProviderCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'sessionsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'usersCount' => [ - ['date' => 1592981250], - ], - 'usersCreate' => [ - ['date' => 1592981250], - ], - 'usersRead' => [ - ['date' => 1592981250], - ], - 'usersUpdate' => [ - ['date' => 1592981250], - ], - 'usersDelete' => [ - ['date' => 1592981250], - ], - 'sessionsCreate' => [ - ['date' => 1592981250], - ], - 'sessionsProviderCreate' => [ - ['date' => 1592981250], - ], - 'sessionsDelete' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageUsersProvider - */ - public function testUsageUsers(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_USERS; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageBucketsProvider(): array - { - return [ - 'basic usage buckets' => [ - [ - 'filesCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesStorage' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'filesCount' => [ - ['date' => 1592981250], - ], - 'filesStorage' => [ - ['date' => 1592981250], - ], - 'filesCreate' => [ - ['date' => 1592981250], - ], - 'filesRead' => [ - ['date' => 1592981250], - ], - 'filesUpdate' => [ - ['date' => 1592981250], - ], - 'filesDelete' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageBucketsProvider - */ - public function testUsageBuckets(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_BUCKETS; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageFunctionsProvider(): array - { - return [ - 'basic usage functions' => [ - [ - 'executionsTotal' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'executionsFailure' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'executionsSuccess' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'executionsTime' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'buildsTotal' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'buildsFailure' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'buildsSuccess' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'buildsTime' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'functionsExecutions' => [ - ['date' => 1592981250], - ], - 'functionsFailures' => [ - ['date' => 1592981250], - ], - 'functionsCompute' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageFunctionsProvider - */ - public function testUsageFunctions(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_FUNCTIONS; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageProjectProvider(): array - { - return [ - 'basic usage project' => [ - [ - 'collections' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'documents' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'executions' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'network' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'requests' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'storage' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'users' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'collections' => [ - ['date' => 1592981250], - ], - 'documents' => [ - ['date' => 1592981250], - ], - 'functions' => [ - ['date' => 1592981250], - ], - 'network' => [ - ['date' => 1592981250], - ], - 'requests' => [ - ['date' => 1592981250], - ], - 'storage' => [ - ['date' => 1592981250], - ], - 'users' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageProjectProvider - */ - public function testUsageProject(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_PROJECT; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function usageStorageProvider(): array - { - return [ - 'basic usage storage' => [ - [ - 'bucketsCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'bucketsCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'bucketsDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'bucketsRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'bucketsUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesCount' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesCreate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesDelete' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesRead' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'storage' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - 'filesUpdate' => [ - ['date' => '2020-06-24T06:47:30.000Z'], - ], - ], - [ - 'bucketsCount' => [ - ['date' => 1592981250], - ], - 'bucketsCreate' => [ - ['date' => 1592981250], - ], - 'bucketsDelete' => [ - ['date' => 1592981250], - ], - 'bucketsRead' => [ - ['date' => 1592981250], - ], - 'bucketsUpdate' => [ - ['date' => 1592981250], - ], - 'filesCount' => [ - ['date' => 1592981250], - ], - 'filesCreate' => [ - ['date' => 1592981250], - ], - 'filesDelete' => [ - ['date' => 1592981250], - ], - 'filesRead' => [ - ['date' => 1592981250], - ], - 'filesStorage' => [ - ['date' => 1592981250], - ], - 'filesUpdate' => [ - ['date' => 1592981250], - ], - ], - ], - ]; - } - - /** - * @dataProvider usageStorageProvider - */ - public function testUsageStorage(array $content, array $expected): void - { - $model = Response::MODEL_USAGE_STORAGE; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - public function userProvider(): array - { - return [ - 'basic user' => [ - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => '2020-06-24T06:47:30.000Z', - '$updatedAt' => '2020-06-24T06:47:30.000Z', - 'name' => 'John Doe', - 'password' => '$argon2id$v=19$m=2048,t=4,p=3$aUZjLnliVWRINmFNTWMudg$5S+x+7uA31xFnrHFT47yFwcJeaP0w92L/4LdgrVRXxE', - 'hash' => 'argon2', - 'hashOptions' => [ - 'memoryCost' => 65536, - 'timeCost' => 4, - 'threads' => 3, - ], - 'registration' => '2020-06-24T06:47:30.000Z', - 'status' => true, - 'passwordUpdate' => '2020-06-24T06:47:30.000Z', - 'email' => 'john@appwrite.io', - 'phone' => '+4930901820', - 'emailVerification' => true, - 'phoneVerification' => true, - 'prefs' => new \stdClass(), - ], - [ - '$id' => '5e5ea5c16897e', - '$createdAt' => 1592981250, - '$updatedAt' => 1592981250, - 'name' => 'John Doe', - 'registration' => 1592981250, - 'status' => true, - 'passwordUpdate' => 1592981250, - 'email' => 'john@appwrite.io', - 'phone' => '+4930901820', - 'emailVerification' => true, - 'phoneVerification' => true, - 'prefs' => new \stdClass(), - ], - ], - ]; - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider userProvider - */ - public function testUser(array $content, array $expected): void - { - $model = Response::MODEL_USER; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - * @dataProvider userProvider - */ - public function testUserList(array $content, array $expected): void - { - $model = Response::MODEL_USER_LIST; - - $content = [ - 'users' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'users' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testWebhook(array $content, array $expected): void - { - $model = Response::MODEL_WEBHOOK; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } - - /** - * @dataProvider createdAtUpdatedAtProvider - */ - public function testWebhookList(array $content, array $expected): void - { - $model = Response::MODEL_WEBHOOK_LIST; - - $content = [ - 'webhooks' => [$content], - 'total' => 1, - ]; - - $expected = [ - 'webhooks' => [$expected], - 'total' => 1, - ]; - - $result = $this->filter->parse($content, $model); - - $this->assertEquals($expected, $result); - } -} diff --git a/tests/unit/Utopia/Response/Filters/V16Test.php b/tests/unit/Utopia/Response/Filters/V16Test.php index 2078559b61..ba6fb837f2 100644 --- a/tests/unit/Utopia/Response/Filters/V16Test.php +++ b/tests/unit/Utopia/Response/Filters/V16Test.php @@ -2,9 +2,8 @@ namespace Tests\Unit\Utopia\Response\Filters; -use Appwrite\Utopia\Response\Filters\V16; -use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; +use Appwrite\Utopia\Response\Filters\V16; use Cron\CronExpression; use PHPUnit\Framework\TestCase; use Utopia\Database\DateTime; diff --git a/tests/unit/Utopia/Response/Filters/V17Test.php b/tests/unit/Utopia/Response/Filters/V17Test.php index 8f618c360e..dedaa996e1 100644 --- a/tests/unit/Utopia/Response/Filters/V17Test.php +++ b/tests/unit/Utopia/Response/Filters/V17Test.php @@ -2,12 +2,9 @@ namespace Tests\Unit\Utopia\Response\Filters; -use Appwrite\Utopia\Response\Filters\V17; -use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Cron\CronExpression; +use Appwrite\Utopia\Response\Filters\V17; use PHPUnit\Framework\TestCase; -use Utopia\Database\DateTime; class V17Test extends TestCase { diff --git a/tests/unit/Utopia/ResponseTest.php b/tests/unit/Utopia/ResponseTest.php index e4389b3953..cd111ec22c 100644 --- a/tests/unit/Utopia/ResponseTest.php +++ b/tests/unit/Utopia/ResponseTest.php @@ -2,11 +2,12 @@ namespace Tests\Unit\Utopia; -use Exception; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Filters\V11; +use Exception; use PHPUnit\Framework\TestCase; use Swoole\Http\Response as SwooleResponse; +use Tests\Unit\Utopia\Response\Filters\First; +use Tests\Unit\Utopia\Response\Filters\Second; use Utopia\Database\Document; class ResponseTest extends TestCase @@ -21,16 +22,30 @@ class ResponseTest extends TestCase $this->response->setModel(new Nested()); } - public function testSetFilter(): void + public function testFilters(): void { - $this->assertEquals($this->response->hasFilter(), false); - $this->assertEquals($this->response->getFilter(), null); + $this->assertFalse($this->response->hasFilters()); + $this->assertIsArray($this->response->getFilters()); + $this->assertEmpty($this->response->getFilters()); - $filter = new V11(); - $this->response->setFilter($filter); + $this->response->addFilter(new First()); + $this->response->addFilter(new Second()); - $this->assertEquals($this->response->hasFilter(), true); - $this->assertEquals($this->response->getFilter(), $filter); + $this->assertTrue($this->response->hasFilters()); + $this->assertCount(2, $this->response->getFilters()); + + $output = $this->response->applyFilters([ + 'initial' => true, + 'first' => false + ], 'test'); + + $this->assertArrayHasKey('initial', $output); + $this->assertTrue($output['initial']); + $this->assertArrayHasKey('first', $output); + $this->assertTrue($output['first']); + $this->assertArrayHasKey('second', $output); + $this->assertTrue($output['second']); + $this->assertArrayNotHasKey('deleted', $output); } public function testResponseModel(): void