From e1cc6bc6249195f96a1f8f1092d650b2a8eee91c Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 15 Aug 2022 16:09:09 +0100 Subject: [PATCH 01/17] Start work on response filters for 0.16 --- app/controllers/general.php | 4 + src/Appwrite/Utopia/Response/Filters/V15.php | 125 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/Appwrite/Utopia/Response/Filters/V15.php diff --git a/app/controllers/general.php b/app/controllers/general.php index 9c2c5d3b81..c3ecfb8737 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -20,6 +20,7 @@ use Appwrite\Utopia\Response\Filters\V11 as ResponseV11; use Appwrite\Utopia\Response\Filters\V12 as ResponseV12; use Appwrite\Utopia\Response\Filters\V13 as ResponseV13; use Appwrite\Utopia\Response\Filters\V14 as ResponseV14; +use Appwrite\Utopia\Response\Filters\V15 as ResponseV15; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; @@ -190,6 +191,9 @@ App::init() case version_compare($responseFormat, '0.14.0', '<='): Response::setFilter(new ResponseV14()); break; + case version_compare($responseFormat, '0.15.0', '<='): + Response::setFilter(new ResponseV15()); + break; default: Response::setFilter(null); } diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php new file mode 100644 index 0000000000..0a6412ab9f --- /dev/null +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -0,0 +1,125 @@ +handleMetricAttributes($content); + } + + return $parsedResponse; + } + + protected function handleMetricAttributes(array $content) + { + $content['timestamp'] = $content['date']; + unset($content['date']); + } + + 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; + } +} From 9f3ebe995648d5f2398a11529e81cd782132309c Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 17 Aug 2022 10:33:35 +0100 Subject: [PATCH 02/17] Continue working on permission backporting --- src/Appwrite/Utopia/Response/Filters/V15.php | 97 ++++++++++---------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 0a6412ab9f..3bf5f9c567 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -59,67 +59,62 @@ class V15 extends Filter unset($content['date']); } - protected function parseRemoveAttributes(array $content, array $attributes) + protected function downgradePermissionSelector(string $permSelector) { - foreach ($attributes as $attribute) { - unset($content[$attribute]); + switch ($permSelector) + { + case 'any': + return 'role:all'; + case 'users': + return 'role:user'; + case 'guests': + return 'role:guest'; } - return $content; + return $permSelector; } - protected function parseRemoveAttributesList(array $content, string $property, array $attributes) + protected function downgradePermissions(array $permissions) { - $documents = $content[$property]; - $parsedResponse = []; - foreach ($documents as $document) { - $parsedResponse[] = $this->parseRemoveAttributes($document, $attributes); + $result = [ + 'read' => [], + 'write' => [] + ]; + + $splitPermissions = []; + + // split up the permisisons + foreach ($permissions as $permission) { + $permission_type = explode('(', $permission)[0]; + $permission_value = explode(')', explode('(', $permission)[1])[0]; + $splitPermissions[$permission_type][] = $permission_value; } - $content[$property] = $parsedResponse; - return $content; - } + // downgrade the permissions + foreach ($permissions as $permission) { + // permission = "read('any')" = ["read" => "role:all"] + $permission_type = explode('(', $permission)[0]; + $permission_value = explode(')', explode('(', $permission)[1])[0]; - 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); + // Old type permissions meant that 'write' is equivalent to 'create', 'update' and 'delete' + switch ($permission_type) + { + case 'update': + case 'delete': + case 'write': + case 'create': + if (!in_array(downgradePermissionSelector($permission_value), $result['write'])) { + $result['write'][] = downgradePermissionSelector($permission_value); + } + break; + case 'read': + if (!in_array(downgradePermissionSelector($permission_value), $result['read'])) { + $result['read'][] = downgradePermissionSelector($permission_value); + } + break; + } } - $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; + return $result; } } From 80ff661aebbdbc1bb9233174e414d38a04f78f5f Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 17 Aug 2022 14:08:09 +0100 Subject: [PATCH 03/17] Continue working on response filters --- app/controllers/general.php | 4 + src/Appwrite/Utopia/Request/Filters/V15.php | 18 +++ src/Appwrite/Utopia/Response/Filters/V15.php | 113 ++++++++++++------- 3 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 src/Appwrite/Utopia/Request/Filters/V15.php diff --git a/app/controllers/general.php b/app/controllers/general.php index c3ecfb8737..a59aee0e63 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -30,6 +30,7 @@ use Utopia\Validator\Hostname; use Appwrite\Utopia\Request\Filters\V12 as RequestV12; use Appwrite\Utopia\Request\Filters\V13 as RequestV13; use Appwrite\Utopia\Request\Filters\V14 as RequestV14; +use Appwrite\Utopia\Request\Filters\V15 as RequestV15; use Utopia\Validator\Text; Config::setParam('domainVerification', false); @@ -65,6 +66,9 @@ App::init() case version_compare($requestFormat, '0.14.0', '<'): Request::setFilter(new RequestV14()); break; + case version_compare($requestFormat, '0.15.0', '<'): + Request::setFilter(new RequestV15()); + break; default: Request::setFilter(null); } diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php new file mode 100644 index 0000000000..8e93d91e2a --- /dev/null +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -0,0 +1,18 @@ +handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'registration', 'passwordUpdate']); + $parsedResponse = $this->handleUser($parsedResponse); + break; case Response::MODEL_METRIC: $parsedResponse = $this->handleMetricAttributes($content); + break; + case Response::MODEL_BUILD: + $parsedResponse = $this->handleDatetimeAttributes($content, ['startTime', 'endTime']); + break; + case Response::MODEL_BUCKET: + case Response::MODEL_COLLECTION: + case Response::MODEL_DEPLOYMENT: + case Response::MODEL_DOCUMENT: + case Response::MODEL_EXECUTION: + case Response::MODEL_PLATFORM: + case Response::MODEL_PROJECT: + case Response::MODEL_TEAM: + case Response::MODEL_FILE: + case Response::MODEL_WEBHOOK: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + break; + case Response::MODEL_FUNCTION: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'scheduleNext', 'schedulePrevious']); + break; + case Response::MODEL_KEY: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); + break; + case Response::MODEL_LOG: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'time']); + break; + case Response::MODEL_MEMBERSHIP: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'invited', 'joined']); + break; + case Response::MODEL_SESSION: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); + break; + case Response::MODEL_TOKEN: + $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', 'expire']); + break; } + // Downgrade Permissions for all models + $parsedResponse = $this->handleDowngradePermissions($parsedResponse); + return $parsedResponse; } + protected function handleDatetimeAttributes(array $content, array $attributes): array + { + foreach ($attributes as $attribute) { + if (isset($content[$attribute])) { + $content[$attribute] = strtotime($content[$attribute]); + } + } + return $content; + } + + protected function handleUser(array $content): array + { + unset($content['password']); + return $content; + } + protected function handleMetricAttributes(array $content) { $content['timestamp'] = $content['date']; unset($content['date']); } + protected function handleDowngradePermissions(array $content) + { + if (!isset($content['$permissions'])) { + return $content; + } + $content = array_merge($content, $this->downgradePermissions($content['permissions'])); + unset($content['permissions']); + return $content; + } + protected function downgradePermissionSelector(string $permSelector) { switch ($permSelector) @@ -77,8 +111,8 @@ class V15 extends Filter protected function downgradePermissions(array $permissions) { $result = [ - 'read' => [], - 'write' => [] + '$read' => [], + '$write' => [] ]; $splitPermissions = []; @@ -92,7 +126,8 @@ class V15 extends Filter // downgrade the permissions foreach ($permissions as $permission) { - // permission = "read('any')" = ["read" => "role:all"] + //TODO: Replace with Permission class + // permission = "read('any')" = ["$read" => "role:all"] $permission_type = explode('(', $permission)[0]; $permission_value = explode(')', explode('(', $permission)[1])[0]; @@ -103,13 +138,13 @@ class V15 extends Filter case 'delete': case 'write': case 'create': - if (!in_array(downgradePermissionSelector($permission_value), $result['write'])) { - $result['write'][] = downgradePermissionSelector($permission_value); + if (!in_array($this->downgradePermissionSelector($permission_value), $result['write'])) { + $result['$write'][] = $this->downgradePermissionSelector($permission_value); } break; case 'read': - if (!in_array(downgradePermissionSelector($permission_value), $result['read'])) { - $result['read'][] = downgradePermissionSelector($permission_value); + if (!in_array($this->downgradePermissionSelector($permission_value), $result['read'])) { + $result['$read'][] = $this->downgradePermissionSelector($permission_value); } break; } From 5294f86595dbc368b5fea75f62e6f4068e3b17d1 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 5 Sep 2022 13:43:36 +0100 Subject: [PATCH 04/17] Run Linter --- src/Appwrite/Utopia/Request/Filters/V15.php | 3 +-- src/Appwrite/Utopia/Response/Filters/V15.php | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index 8e93d91e2a..300750f95e 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -10,9 +10,8 @@ class V15 extends Filter public function parse(array $content, string $model): array { switch ($model) { - } return $content; } -} \ No newline at end of file +} diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index e168e9954a..1ba37ebd20 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -77,7 +77,7 @@ class V15 extends Filter return $content; } - protected function handleMetricAttributes(array $content) + protected function handleMetricAttributes(array $content) { $content['timestamp'] = $content['date']; unset($content['date']); @@ -95,8 +95,7 @@ class V15 extends Filter protected function downgradePermissionSelector(string $permSelector) { - switch ($permSelector) - { + switch ($permSelector) { case 'any': return 'role:all'; case 'users': @@ -132,8 +131,7 @@ class V15 extends Filter $permission_value = explode(')', explode('(', $permission)[1])[0]; // Old type permissions meant that 'write' is equivalent to 'create', 'update' and 'delete' - switch ($permission_type) - { + switch ($permission_type) { case 'update': case 'delete': case 'write': @@ -146,7 +144,7 @@ class V15 extends Filter if (!in_array($this->downgradePermissionSelector($permission_value), $result['read'])) { $result['$read'][] = $this->downgradePermissionSelector($permission_value); } - break; + break; } } From a04a968def96673143a55092ccdd30f513fcb9cd Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 5 Sep 2022 16:48:10 +0100 Subject: [PATCH 05/17] Update permission to use permission class --- src/Appwrite/Utopia/Response/Filters/V15.php | 29 ++++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 1ba37ebd20..19000c9567 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Filters; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Filter; +use Utopia\Database\Permission; class V15 extends Filter { @@ -33,6 +34,7 @@ class V15 extends Filter case Response::MODEL_TEAM: case Response::MODEL_FILE: case Response::MODEL_WEBHOOK: + case Response::MODEL_DOMAIN: $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); break; case Response::MODEL_FUNCTION: @@ -107,31 +109,27 @@ class V15 extends Filter return $permSelector; } - protected function downgradePermissions(array $permissions) + protected function downgradePermissions(array $model) { + if (!isset($model['$permissions'])) { + return $model; + } + + $permissions = $model['$permissions']; + $result = [ '$read' => [], '$write' => [] ]; - $splitPermissions = []; - - // split up the permisisons - foreach ($permissions as $permission) { - $permission_type = explode('(', $permission)[0]; - $permission_value = explode(')', explode('(', $permission)[1])[0]; - $splitPermissions[$permission_type][] = $permission_value; - } - // downgrade the permissions foreach ($permissions as $permission) { - //TODO: Replace with Permission class + $permission = Permission::parse($permission); // permission = "read('any')" = ["$read" => "role:all"] - $permission_type = explode('(', $permission)[0]; - $permission_value = explode(')', explode('(', $permission)[1])[0]; // Old type permissions meant that 'write' is equivalent to 'create', 'update' and 'delete' - switch ($permission_type) { + + switch ($permission->getPermission()) { case 'update': case 'delete': case 'write': @@ -148,6 +146,7 @@ class V15 extends Filter } } - return $result; + unset($model['$permissions']); + return array_merge($model, $result); } } From 80e60d9d95bc896555fe59c8aaa233d5880b72fe Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 7 Sep 2022 11:26:22 +0100 Subject: [PATCH 06/17] Update V15.php --- src/Appwrite/Utopia/Response/Filters/V15.php | 86 +++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 19000c9567..57c8bce4ca 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -25,20 +25,27 @@ class V15 extends Filter $parsedResponse = $this->handleDatetimeAttributes($content, ['startTime', 'endTime']); break; case Response::MODEL_BUCKET: + $parsedResponse = $this->handleBucketAttributes($content); + break; case Response::MODEL_COLLECTION: + $parsedResponse = $this->handleCollectionAttributes($content); + break; case Response::MODEL_DEPLOYMENT: case Response::MODEL_DOCUMENT: case Response::MODEL_EXECUTION: + $parsedResponse = $this->handleExecutionAttributes($content); + break; case Response::MODEL_PLATFORM: case Response::MODEL_PROJECT: case Response::MODEL_TEAM: case Response::MODEL_FILE: case Response::MODEL_WEBHOOK: case Response::MODEL_DOMAIN: + case Response::MODEL_DATABASE: $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); break; case Response::MODEL_FUNCTION: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'scheduleNext', 'schedulePrevious']); + $parsedResponse = $this->handleFunctionAttribtues($content); break; case Response::MODEL_KEY: $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); @@ -55,6 +62,8 @@ class V15 extends Filter case Response::MODEL_TOKEN: $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', 'expire']); break; + case Response::MODEL_USAGE_FUNCTIONS: + $parsedResponse = $this->handleModelUsageFuncAttributes($content); } // Downgrade Permissions for all models @@ -63,6 +72,20 @@ class V15 extends Filter return $parsedResponse; } + protected function handleBucketAttributes(array $content) + { + if ($content['fileSecurity']) { + $content['permssion'] = 'file'; + } else { + $content['permssion'] = 'bucket'; + } + + unset($content['fileSecurity']); + unset($content['compression']); + + $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + } + protected function handleDatetimeAttributes(array $content, array $attributes): array { foreach ($attributes as $attribute) { @@ -76,6 +99,10 @@ class V15 extends Filter protected function handleUser(array $content): array { unset($content['password']); + unset($content['hash']); + unset($content['hashOptions']); + + $content = $this->handleDatetimeAttributes($content, ['registration', 'passwordUpdate', '$createdAt', '$updatedAt']); return $content; } @@ -149,4 +176,61 @@ class V15 extends Filter unset($model['$permissions']); return array_merge($model, $result); } + + protected function handleCollectionAttributes(array $content) + { + $content['permission'] = $content['documentSecurity']; + + unset($content['documentSecurity']); + $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + return $content; + } + + private function handleExecutionAttributes($content) + { + unset($content['stdout']); + + $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + return $content; + } + + private function handleFunctionAttribtues($content) + { + $content['execute'] = array_map($this->downgradePermissionSelector, $content['execute']); + + $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'scheduleNext', 'schedulePrevious']); + return $content; + } + + private function handleModelUsageFuncAttributes($content) + { + $content['functiosnExecutions'] = $content['executionsTotal']; + $content['functionsFailures'] = $content['executionsFailure']; + $content['functionsCompute'] = $content['executionsTime']; + 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 handleUsageProjectAttributes($content) + { + $content['functions'] = $content['executions']; + unset($content['executions']); + + return $content; + } + + private function handleUsageStorageAttribtues($content) + { + $content['filesStorage'] = $content['storage']; + $content['tagsStorage'] = []; + unset($content['storage']); + } } From 7d3829e35ff27e4ad3140f7be040b93d08372b95 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 8 Sep 2022 12:33:20 +0100 Subject: [PATCH 07/17] Update V15.php --- src/Appwrite/Utopia/Request/Filters/V15.php | 74 +++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index 300750f95e..9170386280 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -3,6 +3,7 @@ namespace Appwrite\Utopia\Request\Filters; use Appwrite\Utopia\Request\Filter; +use Utopia\Database\Query; class V15 extends Filter { @@ -10,8 +11,81 @@ class V15 extends Filter public function parse(array $content, string $model): array { switch ($model) { + // Old Query -> New Query + case "account.logs": + $content = $this->handleAccountLogs($content); + break; + case "account.initials": + $content = $this->handleInitials($content); } return $content; } + + protected function handleAccountLogs($content) + { + // Translate Old Query System to New Query System + + if (!empty($content['limit'])) { + $content['queries'][] = 'Query.limit('.$content['limit'].')'; + } + + if (!empty($content['offset'])) { + $content['queries'][] = 'Query.offset('.$content['offset'].')'; + } + + unset($content['limit']); + unset($content['offset']); + + return $content; + } + + protected function handleInitials($content) + { + unset($content[' color']); + + return $content; + } + + protected function handleQueryTranslation($content) { + $content['queries'] = []; + + if (isset($content['limit'])) { + $content['queries'][] = Query::limit($content['limit']); + } + + if (isset($content['offset'])) { + $content['queries'][] = Query::offset($content['offset']); + } + + if (isset($content['cursor'])) { + $direction = $content['cursorDirection'] ?? 'after'; + + if ($direction === 'after') { + $content['queries'][] = Query::cursorAfter($content['cursor']); + } else { + $content['queries'][] = Query::cursorBefore($content['cursor']); + } + } + + if (isset($content['orderAttributes'])) { + foreach ($content['orderAttributes'] as $i=>$attribute) { + if ($content['orderTypes'][$i] === 'ASC') { + $content['queries'][] = Query::orderAsc($attribute); + } else if ($content['orderTypes'][$i] === 'DESC') { + $content['queries'][] = Query::orderDesc($attribute); + } else { + continue; + } + } + } + + unset($content['limit']); + unset($content['offset']); + unset($content['cursor']); + unset($content['orderAttributes']); + unset($content['orderTypes']); + + return $content; + } } From ddd15921a3795869d0e0528ae53f0d6dfd070580 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 8 Sep 2022 23:55:29 +0000 Subject: [PATCH 08/17] Update V15 request filters Request filters are in place for the following services: * account * databases * functions * projects --- src/Appwrite/Utopia/Request/Filters/V15.php | 244 ++++++-- tests/unit/Utopia/Request/Filters/V15Test.php | 570 ++++++++++++++++++ 2 files changed, 770 insertions(+), 44 deletions(-) create mode 100644 tests/unit/Utopia/Request/Filters/V15Test.php diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index 9170386280..b6b2497fba 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -3,7 +3,7 @@ namespace Appwrite\Utopia\Request\Filters; use Appwrite\Utopia\Request\Filter; -use Utopia\Database\Query; +use Utopia\Database\Database; class V15 extends Filter { @@ -11,27 +11,64 @@ class V15 extends Filter public function parse(array $content, string $model): array { switch ($model) { - // Old Query -> New Query - case "account.logs": - $content = $this->handleAccountLogs($content); + case 'account.logs': + case 'databases.listLogs': + case 'databases.listCollectionLogs': + case 'databases.listDocumentLogs': + $content = $this->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': + $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': + $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 "account.initials": - $content = $this->handleInitials($content); } return $content; } - protected function handleAccountLogs($content) + protected function convertLimitAndOffset($content) { - // Translate Old Query System to New Query System + if (isset($content['limit'])) { + $content['queries'][] = 'limit(' . $content['limit'] . ')'; + } - if (!empty($content['limit'])) { - $content['queries'][] = 'Query.limit('.$content['limit'].')'; - } - - if (!empty($content['offset'])) { - $content['queries'][] = 'Query.offset('.$content['offset'].')'; + if (isset($content['offset'])) { + $content['queries'][] = 'offset(' . $content['offset'] . ')'; } unset($content['limit']); @@ -40,52 +77,171 @@ class V15 extends Filter return $content; } - protected function handleInitials($content) + protected function convertCursor($content) { - unset($content[' color']); + 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 handleQueryTranslation($content) { - $content['queries'] = []; - - if (isset($content['limit'])) { - $content['queries'][] = Query::limit($content['limit']); - } - - if (isset($content['offset'])) { - $content['queries'][] = Query::offset($content['offset']); - } - - if (isset($content['cursor'])) { - $direction = $content['cursorDirection'] ?? 'after'; - - if ($direction === 'after') { - $content['queries'][] = Query::cursorAfter($content['cursor']); + protected function convertOrderType($content) + { + if (isset($content['orderType'])) { + if ($content['orderType'] === Database::ORDER_DESC) { + $content['queries'][] = 'orderDesc("")'; } else { - $content['queries'][] = Query::cursorBefore($content['cursor']); + $content['queries'][] = 'orderAsc("")'; } } + unset($content['orderType']); - if (isset($content['orderAttributes'])) { - foreach ($content['orderAttributes'] as $i=>$attribute) { - if ($content['orderTypes'][$i] === 'ASC') { - $content['queries'][] = Query::orderAsc($attribute); - } else if ($content['orderTypes'][$i] === 'DESC') { - $content['queries'][] = Query::orderDesc($attribute); + 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 { - continue; + $content['queries'][] = 'orderAsc("' . $attribute . '")'; } } } - - unset($content['limit']); - unset($content['offset']); - unset($content['cursor']); + 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'][] = 'read("any")'; + } elseif ($read === 'role:guest') { + $content['permissions'][] = 'read("guests")'; + } elseif ($read === 'role:member') { + $content['permissions'][] = 'read("users")'; + } elseif (str_contains($read, ':')) { + $content['permissions'][] = 'read("' . $read . '")'; + } + } + } + + if (isset($content['write'])) { + foreach ($content['write'] as $write) { + if ($write === 'role:all' || $write === 'role:member') { + $content['permissions'][] = 'write("users")'; + } elseif ($write === 'role:guest') { + // don't add because, historically, + // role:guest for write did nothing + } elseif (str_contains($write, ':')) { + $content['permissions'][] = 'write("' . $write . '")'; + } + } + } + + unset($content['read']); + unset($content['write']); + + return $content; + } + + protected function convertFilters($content) + { + if (!isset($content['queries'])) { + return $content; + } + + $operations = [ + 'equal' => 'equal', + 'notEqual' => 'notEqual', + 'lesser' => 'lessThan', + 'lesserEqual' => 'lessThanEqual', + 'greater' => 'greaterThan', + 'greaterEqual' => 'greaterThanEqual', + 'search' => '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[] = 'users'; + } 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; + } } diff --git a/tests/unit/Utopia/Request/Filters/V15Test.php b/tests/unit/Utopia/Request/Filters/V15Test.php new file mode 100644 index 0000000000..1c8552d73d --- /dev/null +++ b/tests/unit/Utopia/Request/Filters/V15Test.php @@ -0,0 +1,570 @@ +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 testGetAccountLogs(array $content, array $expected): void + { + $model = 'account.logs'; + + $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 permissionProvider(): 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 permissionProvider + * @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 permissionProvider + * @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, 'fail'); + } + + /** + * @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); + } +} From 668ebe4f4192c6392db35382adb055361105e522 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Fri, 9 Sep 2022 17:44:57 +0000 Subject: [PATCH 09/17] Update V15 request filters for storage, teams, and users --- composer.json | 8 +- composer.lock | 92 +++++---- src/Appwrite/Utopia/Request/Filters/V15.php | 56 ++++-- tests/unit/Utopia/Request/Filters/V15Test.php | 186 +++++++++++++++++- 4 files changed, 274 insertions(+), 68 deletions(-) diff --git a/composer.json b/composer.json index 8fe79a7ace..4598a51ea5 100644 --- a/composer.json +++ b/composer.json @@ -45,13 +45,13 @@ "appwrite/php-runtimes": "0.11.*", "utopia-php/framework": "0.21.*", "utopia-php/logger": "0.3.*", - "utopia-php/abuse": "0.12.*", + "utopia-php/abuse": "0.13.*", "utopia-php/analytics": "0.2.*", - "utopia-php/audit": "0.13.*", + "utopia-php/audit": "0.14.*", "utopia-php/cache": "0.6.*", "utopia-php/cli": "0.13.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.24.*", + "utopia-php/database": "0.25.*", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", @@ -77,7 +77,7 @@ } ], "require-dev": { - "appwrite/sdk-generator": "0.23.0", + "appwrite/sdk-generator": "0.25.0", "ext-fileinfo": "*", "phpunit/phpunit": "9.5.20", "squizlabs/php_codesniffer": "^3.6", diff --git a/composer.lock b/composer.lock index 5d2cef66f0..58bc100ead 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": "39c0ee0169b4681e5c07889d2a285d01", + "content-hash": "6194919aa35d896dc3dfdb846936cba4", "packages": [ { "name": "adhocore/jwt", @@ -1591,25 +1591,25 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.1.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", - "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1638,7 +1638,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -1654,7 +1654,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/polyfill-php80", @@ -1741,23 +1741,23 @@ }, { "name": "utopia-php/abuse", - "version": "0.12.0", + "version": "0.13.1", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "aa1e1aae163ecf8ea81d48857ff55c241dcb695f" + "reference": "4c1b8fe742f17158c59550cdfd9074a94bf474ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/aa1e1aae163ecf8ea81d48857ff55c241dcb695f", - "reference": "aa1e1aae163ecf8ea81d48857ff55c241dcb695f", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/4c1b8fe742f17158c59550cdfd9074a94bf474ac", + "reference": "4c1b8fe742f17158c59550cdfd9074a94bf474ac", "shasum": "" }, "require": { "ext-curl": "*", "ext-pdo": "*", "php": ">=8.0", - "utopia-php/database": "0.24.0" + "utopia-php/database": "0.25.*" }, "require-dev": { "phpunit/phpunit": "^9.4", @@ -1789,9 +1789,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.12.0" + "source": "https://github.com/utopia-php/abuse/tree/0.13.1" }, - "time": "2022-08-27T09:50:09+00:00" + "time": "2022-09-07T16:02:58+00:00" }, { "name": "utopia-php/analytics", @@ -1850,22 +1850,22 @@ }, { "name": "utopia-php/audit", - "version": "0.13.0", + "version": "0.14.1", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b" + "reference": "b011224ed9bfef7e5c849938e65619af28f7cf41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b", - "reference": "a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/b011224ed9bfef7e5c849938e65619af28f7cf41", + "reference": "b011224ed9bfef7e5c849938e65619af28f7cf41", "shasum": "" }, "require": { "ext-pdo": "*", "php": ">=8.0", - "utopia-php/database": "0.24.0" + "utopia-php/database": "0.25.*" }, "require-dev": { "phpunit/phpunit": "^9.3", @@ -1897,9 +1897,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.13.0" + "source": "https://github.com/utopia-php/audit/tree/0.14.1" }, - "time": "2022-08-27T09:18:57+00:00" + "time": "2022-09-07T16:03:16+00:00" }, { "name": "utopia-php/cache", @@ -2060,16 +2060,16 @@ }, { "name": "utopia-php/database", - "version": "0.24.0", + "version": "0.25.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "7da841d65d87e9f2c242589e58c38880def44dd8" + "reference": "140bbedf1c4d622990fb94d26681fcca235cd5b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/7da841d65d87e9f2c242589e58c38880def44dd8", - "reference": "7da841d65d87e9f2c242589e58c38880def44dd8", + "url": "https://api.github.com/repos/utopia-php/database/zipball/140bbedf1c4d622990fb94d26681fcca235cd5b9", + "reference": "140bbedf1c4d622990fb94d26681fcca235cd5b9", "shasum": "" }, "require": { @@ -2118,9 +2118,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.24.0" + "source": "https://github.com/utopia-php/database/tree/0.25.2" }, - "time": "2022-08-27T09:16:05+00:00" + "time": "2022-09-09T03:58:01+00:00" }, { "name": "utopia-php/domains", @@ -2178,16 +2178,16 @@ }, { "name": "utopia-php/framework", - "version": "0.21.0", + "version": "0.21.1", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "5aa5431788460a782065e42b0e8a35e7f139af2f" + "reference": "c81789b87a917da2daf336738170ebe01f50ea18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/5aa5431788460a782065e42b0e8a35e7f139af2f", - "reference": "5aa5431788460a782065e42b0e8a35e7f139af2f", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/c81789b87a917da2daf336738170ebe01f50ea18", + "reference": "c81789b87a917da2daf336738170ebe01f50ea18", "shasum": "" }, "require": { @@ -2221,9 +2221,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.21.0" + "source": "https://github.com/utopia-php/framework/tree/0.21.1" }, - "time": "2022-08-12T11:37:21+00:00" + "time": "2022-09-07T09:56:28+00:00" }, { "name": "utopia-php/image", @@ -2840,16 +2840,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.23.0", + "version": "0.25.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "efadccb9abd6263d045ef157881143d3a59dc710" + "reference": "91e2b9bfb06521faabd610935cbfc1825110666a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/efadccb9abd6263d045ef157881143d3a59dc710", - "reference": "efadccb9abd6263d045ef157881143d3a59dc710", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/91e2b9bfb06521faabd610935cbfc1825110666a", + "reference": "91e2b9bfb06521faabd610935cbfc1825110666a", "shasum": "" }, "require": { @@ -2884,9 +2884,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/0.23.0" + "source": "https://github.com/appwrite/sdk-generator/tree/0.25.0" }, - "time": "2022-09-04T17:29:33+00:00" + "time": "2022-09-06T16:32:52+00:00" }, { "name": "doctrine/instantiator", @@ -5382,7 +5382,13 @@ "ext-fileinfo": "*" }, "platform-overrides": { - "php": "8.0" + "php": "8.0", + "ext-imagick": "3.7.0", + "ext-yaml": "2.2.2", + "ext-redis": "5.3.7", + "ext-swoole": "4.8.10", + "ext-zstd": "0.11.0", + "ext-mongodb": "1.13.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index b6b2497fba..d9e6df8be3 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -4,6 +4,9 @@ namespace Appwrite\Utopia\Request\Filters; use Appwrite\Utopia\Request\Filter; use Utopia\Database\Database; +use Utopia\Database\Permission; +use Utopia\Database\Query; +use Utopia\Database\Role; class V15 extends Filter { @@ -15,6 +18,8 @@ class V15 extends Filter case 'databases.listLogs': case 'databases.listCollectionLogs': case 'databases.listDocumentLogs': + case 'teams.listLogs': + case 'users.getLogs': $content = $this->convertLimitAndOffset($content); break; case 'account.initials': @@ -25,6 +30,11 @@ class V15 extends Filter case 'functions.list': case 'functions.listDeployments': case 'projects.list': + case 'storage.listBuckets': + case 'storage.listFiles': + case 'teams.list': + case 'teams.getMemberships': + case 'users.list': $content = $this->convertLimitAndOffset($content); $content = $this->convertCursor($content); $content = $this->convertOrderType($content); @@ -36,6 +46,8 @@ class V15 extends Filter break; case 'databases.createDocument': case 'databases.updateDocument': + case 'storage.createFile': + case 'storage.updateFile': $content = $this->convertReadWrite($content); break; case 'databases.listDocuments': @@ -56,6 +68,11 @@ class V15 extends Filter 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; @@ -145,13 +162,13 @@ class V15 extends Filter if (isset($content['read'])) { foreach ($content['read'] as $read) { if ($read === 'role:all') { - $content['permissions'][] = 'read("any")'; + $content['permissions'][] = Permission::read(Role::any()); } elseif ($read === 'role:guest') { - $content['permissions'][] = 'read("guests")'; + $content['permissions'][] = Permission::read(Role::guests()); } elseif ($read === 'role:member') { - $content['permissions'][] = 'read("users")'; + $content['permissions'][] = Permission::read(Role::users()); } elseif (str_contains($read, ':')) { - $content['permissions'][] = 'read("' . $read . '")'; + $content['permissions'][] = Permission::read(Role::parse($read)); } } } @@ -159,12 +176,12 @@ class V15 extends Filter if (isset($content['write'])) { foreach ($content['write'] as $write) { if ($write === 'role:all' || $write === 'role:member') { - $content['permissions'][] = 'write("users")'; + $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'][] = 'write("' . $write . '")'; + $content['permissions'][] = Permission::write(Role::parse($write)); } } } @@ -182,13 +199,13 @@ class V15 extends Filter } $operations = [ - 'equal' => 'equal', - 'notEqual' => 'notEqual', - 'lesser' => 'lessThan', - 'lesserEqual' => 'lessThanEqual', - 'greater' => 'greaterThan', - 'greaterEqual' => 'greaterThanEqual', - 'search' => 'search', + 'equal' => Query::TYPE_EQUAL, + 'notEqual' => Query::TYPE_NOTEQUAL, + 'lesser' => Query::TYPE_LESSER, + 'lesserEqual' => Query::TYPE_LESSEREQUAL, + 'greater' => Query::TYPE_GREATER, + 'greaterEqual' => Query::TYPE_GREATEREQUAL, + 'search' => Query::TYPE_SEARCH, ]; foreach ($content['queries'] as $i => $query) { foreach ($operations as $oldOperation => $newOperation) { @@ -215,7 +232,7 @@ class V15 extends Filter $execute = []; foreach ($content['execute'] as $role) { if ($role === 'role:all' || $role === 'role:member') { - $execute[] = 'users'; + $execute[] = Role::users()->toString(); } elseif ($role === 'role:guest') { // don't add because, historically, // role:guest for write did nothing @@ -244,4 +261,15 @@ class V15 extends Filter return $content; } + + protected function convertBucketPermission($content) + { + if (isset($content['permission'])) { + $content['fileSecurity'] = $content['permission'] === 'file'; + } + + unset($content['permission']); + + return $content; + } } diff --git a/tests/unit/Utopia/Request/Filters/V15Test.php b/tests/unit/Utopia/Request/Filters/V15Test.php index 1c8552d73d..28bdda3911 100644 --- a/tests/unit/Utopia/Request/Filters/V15Test.php +++ b/tests/unit/Utopia/Request/Filters/V15Test.php @@ -1,6 +1,6 @@ assertEquals($expected, $result); } - public function permissionProvider(): array + public function collectionPermissionProvider(): array { return [ 'permission collection' => [ @@ -244,7 +244,7 @@ class V15Test extends TestCase } /** - * @dataProvider permissionProvider + * @dataProvider collectionPermissionProvider * @dataProvider readWriteProvider */ public function testCreateCollection(array $content, array $expected): void @@ -284,7 +284,7 @@ class V15Test extends TestCase } /** - * @dataProvider permissionProvider + * @dataProvider collectionPermissionProvider * @dataProvider readWriteProvider */ public function testUpdateCollection(array $content, array $expected): void @@ -389,7 +389,7 @@ class V15Test extends TestCase $result = $this->filter->parse($content, $model); - $this->assertEquals($expected, $result, 'fail'); + $this->assertEquals($expected, $result); } /** @@ -416,7 +416,8 @@ class V15Test extends TestCase $this->assertEquals($expected, $result); } - public function executeProvider() : array { + public function executeProvider(): array + { return [ 'all roles' => [ [ @@ -526,7 +527,7 @@ class V15Test extends TestCase $this->assertEquals($expected, $result); } - public function expireProvider() : array + public function expireProvider(): array { return [ 'empty' => [ @@ -567,4 +568,175 @@ class V15Test extends TestCase $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 testGetTeamMemberships(array $content, array $expected): void + { + $model = 'teams.getMemberships'; + + $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 testGetUserLogs(array $content, array $expected): void + { + $model = 'users.getLogs'; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } } From 71206a98864fd95349c0e5024fb0428a9c4891d3 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sat, 10 Sep 2022 01:00:20 +0000 Subject: [PATCH 10/17] Update V15 response filter and add tests --- src/Appwrite/Utopia/Response/Filters/V15.php | 262 +++-- src/Appwrite/Utopia/Response/Model/Metric.php | 11 +- tests/unit/Utopia/Request/Filters/V15Test.php | 2 +- .../unit/Utopia/Response/Filters/V15Test.php | 912 ++++++++++++++++++ 4 files changed, 1089 insertions(+), 98 deletions(-) create mode 100644 tests/unit/Utopia/Response/Filters/V15Test.php diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 57c8bce4ca..f28200d388 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -4,7 +4,9 @@ namespace Appwrite\Utopia\Response\Filters; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Filter; +use Utopia\Database\Database; use Utopia\Database\Permission; +use Utopia\Database\Role; class V15 extends Filter { @@ -14,26 +16,28 @@ class V15 extends Filter $parsedResponse = $content; switch ($model) { + case Response::MODEL_ACCOUNT: case Response::MODEL_USER: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'registration', 'passwordUpdate']); - $parsedResponse = $this->handleUser($parsedResponse); + $parsedResponse = $this->parseUser($parsedResponse); break; case Response::MODEL_METRIC: - $parsedResponse = $this->handleMetricAttributes($content); + $parsedResponse = $this->parseMetric($parsedResponse); break; case Response::MODEL_BUILD: - $parsedResponse = $this->handleDatetimeAttributes($content, ['startTime', 'endTime']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['startTime', 'endTime']); break; case Response::MODEL_BUCKET: - $parsedResponse = $this->handleBucketAttributes($content); + $parsedResponse = $this->parseBucket($parsedResponse); break; case Response::MODEL_COLLECTION: - $parsedResponse = $this->handleCollectionAttributes($content); + $parsedResponse = $this->parseCollection($parsedResponse); break; case Response::MODEL_DEPLOYMENT: case Response::MODEL_DOCUMENT: + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt']); + break; case Response::MODEL_EXECUTION: - $parsedResponse = $this->handleExecutionAttributes($content); + $parsedResponse = $this->parseExecution($parsedResponse); break; case Response::MODEL_PLATFORM: case Response::MODEL_PROJECT: @@ -42,51 +46,62 @@ class V15 extends Filter case Response::MODEL_WEBHOOK: case Response::MODEL_DOMAIN: case Response::MODEL_DATABASE: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt']); break; case Response::MODEL_FUNCTION: - $parsedResponse = $this->handleFunctionAttribtues($content); + $parsedResponse = $this->parseFunction($parsedResponse); break; case Response::MODEL_KEY: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt', 'expire']); break; case Response::MODEL_LOG: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'time']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt', 'time']); break; case Response::MODEL_MEMBERSHIP: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'invited', 'joined']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt', 'invited', 'joined']); break; case Response::MODEL_SESSION: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); break; case Response::MODEL_TOKEN: - $parsedResponse = $this->handleDatetimeAttributes($content, ['$createdAt', 'expire']); + $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', 'expire']); break; case Response::MODEL_USAGE_FUNCTIONS: - $parsedResponse = $this->handleModelUsageFuncAttributes($content); + $parsedResponse = $this->parseModelUsageFunc($parsedResponse); + break; + case Response::MODEL_USAGE_PROJECT: + $parsedResponse = $this->parseUsageProject($parsedResponse); + break; + case Response::MODEL_USAGE_STORAGE: + $parsedResponse = $this->parseUsageStorage($parsedResponse); + break; } // Downgrade Permissions for all models - $parsedResponse = $this->handleDowngradePermissions($parsedResponse); + $parsedResponse = $this->parsePermissions($parsedResponse); return $parsedResponse; } - protected function handleBucketAttributes(array $content) + protected function parseBucket(array $content) { - if ($content['fileSecurity']) { - $content['permssion'] = 'file'; - } else { - $content['permssion'] = 'bucket'; + if (isset($content['fileSecurity'])) { + if ($content['fileSecurity']) { + $content['permission'] = 'file'; + } else { + $content['permission'] = 'bucket'; + } } unset($content['fileSecurity']); unset($content['compression']); - $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + + return $content; } - protected function handleDatetimeAttributes(array $content, array $attributes): array + protected function parseDatetimeAttributes(array $content, array $attributes): array { foreach ($attributes as $attribute) { if (isset($content[$attribute])) { @@ -96,117 +111,141 @@ class V15 extends Filter return $content; } - protected function handleUser(array $content): array + protected function parseUser(array $content): array { unset($content['password']); unset($content['hash']); unset($content['hashOptions']); - $content = $this->handleDatetimeAttributes($content, ['registration', 'passwordUpdate', '$createdAt', '$updatedAt']); + $content = $this->parseDatetimeAttributes($content, ['registration', 'passwordUpdate', '$createdAt', '$updatedAt']); return $content; } - protected function handleMetricAttributes(array $content) + protected function parseMetric(array $content) { - $content['timestamp'] = $content['date']; - unset($content['date']); + $content = $this->parseDatetimeAttributes($content, ['date']); + return $content; } - protected function handleDowngradePermissions(array $content) + protected function parsePermissions(array $content) { if (!isset($content['$permissions'])) { return $content; } - $content = array_merge($content, $this->downgradePermissions($content['permissions'])); - unset($content['permissions']); - return $content; - } - protected function downgradePermissionSelector(string $permSelector) - { - switch ($permSelector) { - case 'any': - return 'role:all'; - case 'users': - return 'role:user'; - case 'guests': - return 'role:guest'; - } - - return $permSelector; - } - - protected function downgradePermissions(array $model) - { - if (!isset($model['$permissions'])) { - return $model; - } - - $permissions = $model['$permissions']; - - $result = [ - '$read' => [], - '$write' => [] - ]; + $read = []; + $write = []; // downgrade the permissions - foreach ($permissions as $permission) { + foreach ($content['$permissions'] as $permission) { $permission = Permission::parse($permission); - // permission = "read('any')" = ["$read" => "role:all"] + $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 'update': - case 'delete': - case 'write': - case 'create': - if (!in_array($this->downgradePermissionSelector($permission_value), $result['write'])) { - $result['$write'][] = $this->downgradePermissionSelector($permission_value); - } + case Database::PERMISSION_UPDATE: + case Database::PERMISSION_DELETE: + case Database::PERMISSION_WRITE: + case Database::PERMISSION_CREATE: + $write[$this->parseRole($permission_value)] = true; break; - case 'read': - if (!in_array($this->downgradePermissionSelector($permission_value), $result['read'])) { - $result['$read'][] = $this->downgradePermissionSelector($permission_value); - } + case Database::PERMISSION_READ: + $read[$this->parseRole($permission_value)] = true; break; } } - unset($model['$permissions']); - return array_merge($model, $result); + $content['$read'] = array_keys($read); + $content['$write'] = array_keys($write); + + unset($content['$permissions']); + + return $content; } - protected function handleCollectionAttributes(array $content) + protected function parseRole(string $role) { - $content['permission'] = $content['documentSecurity']; + 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->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); return $content; } - private function handleExecutionAttributes($content) + private function parseExecution($content) { unset($content['stdout']); - - $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'startTime', 'endTime']); return $content; } - private function handleFunctionAttribtues($content) + private function parseFunction($content) { - $content['execute'] = array_map($this->downgradePermissionSelector, $content['execute']); + if (isset($content['execute'])) { + foreach ($content['execute'] as $i => $role) { + $content['execute'][$i] = $this->parseRole($role); + } + } - $content = $this->handleDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'scheduleNext', 'schedulePrevious']); + if (isset($content['vars'])) { + $vars = []; + foreach ($content['vars'] as $i => $var) { + $vars[$var['key']] = $var['value']; + } + $content['vars'] = $vars; + } + + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'scheduleNext', 'schedulePrevious']); return $content; } - private function handleModelUsageFuncAttributes($content) + private function parseModelUsageFunc($content) { - $content['functiosnExecutions'] = $content['executionsTotal']; - $content['functionsFailures'] = $content['executionsFailure']; - $content['functionsCompute'] = $content['executionsTime']; + $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']); @@ -219,18 +258,59 @@ class V15 extends Filter return $content; } - private function handleUsageProjectAttributes($content) + private function parseUsageProject($content) { $content['functions'] = $content['executions']; unset($content['executions']); + $usage = [ + 'collections', + 'documents', + 'functions', + 'network', + 'requests', + 'storage', + 'users', + ]; + + foreach ($usage as $name) { + $data = []; + foreach ($content[$name] as $metric) { + $data[] = $this->parseMetric($metric); + } + $content[$name] = $data; + } + return $content; } - private function handleUsageStorageAttribtues($content) + private function parseUsageStorage($content) { $content['filesStorage'] = $content['storage']; - $content['tagsStorage'] = []; unset($content['storage']); + + $usage = [ + 'bucketsCount', + 'bucketsCreate', + 'bucketsDelete', + 'bucketsRead', + 'bucketsUpdate', + 'filesCount', + 'filesCreate', + 'filesDelete', + 'filesRead', + 'filesStorage', + 'filesUpdate', + ]; + + foreach ($usage as $name) { + $data = []; + foreach ($content[$name] as $metric) { + $data[] = $this->parseMetric($metric); + } + $content[$name] = $data; + } + + return $content; } } diff --git a/src/Appwrite/Utopia/Response/Model/Metric.php b/src/Appwrite/Utopia/Response/Model/Metric.php index 7fb1b98386..16cf7f7df2 100644 --- a/src/Appwrite/Utopia/Response/Model/Metric.php +++ b/src/Appwrite/Utopia/Response/Model/Metric.php @@ -17,12 +17,11 @@ class Metric extends Model 'example' => 1, ]) ->addRule('date', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'The UNIX timestamp at which this metric was aggregated.', - 'default' => 0, - 'example' => 1592981250 - ]) - ; + 'type' => self::TYPE_DATETIME, + 'description' => 'The date at which this metric was aggregated in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE + ]); } /** diff --git a/tests/unit/Utopia/Request/Filters/V15Test.php b/tests/unit/Utopia/Request/Filters/V15Test.php index 28bdda3911..1617c2b0c5 100644 --- a/tests/unit/Utopia/Request/Filters/V15Test.php +++ b/tests/unit/Utopia/Request/Filters/V15Test.php @@ -1,6 +1,6 @@ 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); + } + + 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); + } + + 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 + */ + 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 testDeployment(array $content, array $expected): void + { + $model = Response::MODEL_DEPLOYMENT; + + $result = $this->filter->parse($content, $model); + + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider createdAtUpdatedAtProvider + * @dataProvider permissionsProvider + */ + public function testDocument(array $content, array $expected): void + { + $model = Response::MODEL_DOCUMENT; + + $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); + } + + public function executionProvider(): array + { + return [ + 'basic execution' => [ + ['stdout' => ''], + [], + ], + ]; + } + + /** + * @dataProvider createdAtUpdatedAtProvider + * @dataProvider permissionsProvider + * @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 permissionsProvider + */ + public function testFile(array $content, array $expected): void + { + $model = Response::MODEL_FILE; + + $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', + 'status' => 'enabled', + '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 + ], + ], + ]; + } + + /** + * @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); + } + + 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); + } + + public function logProvider(): array + { + return [ + 'basic log' => [ + ['time' => '2020-06-24T06:47:30.000Z'], + ['time' => 1592981250], + ], + ]; + } + + /** + * @dataProvider createdAtUpdatedAtProvider + * @dataProvider logProvider + */ + public function testLog(array $content, array $expected): void + { + $model = Response::MODEL_LOG; + + $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); + } + + 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 testProject(array $content, array $expected): void + { + $model = Response::MODEL_PROJECT; + + $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, + ], + ], + ]; + } + + /** + * @dataProvider sessionProvider + */ + public function testSession(array $content, array $expected): void + { + $model = Response::MODEL_SESSION; + + $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); + } + + 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 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); + } +} From 79b57cf69634c2e73efb39cfa2da32585bf4420b Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 12 Sep 2022 19:07:08 +0000 Subject: [PATCH 11/17] Update response filters for list models --- src/Appwrite/Utopia/Response/Filters/V15.php | 164 +++++- .../unit/Utopia/Response/Filters/V15Test.php | 519 ++++++++++++++++++ 2 files changed, 666 insertions(+), 17 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index f28200d388..047eb1d268 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -20,48 +20,134 @@ class V15 extends Filter case Response::MODEL_USER: $parsedResponse = $this->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->parseDatetimeAttributes($parsedResponse, ['startTime', 'endTime']); + $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->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt']); + case Response::MODEL_FILE: + $parsedResponse = $this->parsePermissionsCreatedAtUpdatedAt($parsedResponse); + break; + case Response::MODEL_DOCUMENT_LIST: + case Response::MODEL_FILE_LIST: + $listKey = ''; + switch ($model) { + case Response::MODEL_DOCUMENT_LIST: + $listKey = 'documents'; + break; + case Response::MODEL_FILE_LIST: + $listKey = 'files'; + break; + } + $parsedResponse[$listKey] = array_map(fn ($content) => $this->parsePermissionsCreatedAtUpdatedAt($content), $parsedResponse[$listKey]); break; case Response::MODEL_EXECUTION: $parsedResponse = $this->parseExecution($parsedResponse); break; - case Response::MODEL_PLATFORM: - case Response::MODEL_PROJECT: - case Response::MODEL_TEAM: - case Response::MODEL_FILE: - case Response::MODEL_WEBHOOK: - case Response::MODEL_DOMAIN: - case Response::MODEL_DATABASE: - $parsedResponse = $this->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt']); + 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->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt', 'expire']); + $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->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt', 'time']); + $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->parseDatetimeAttributes($parsedResponse, ['$createdAt', '$updatedAt', 'invited', 'joined']); + $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->parseDatetimeAttributes($parsedResponse, ['$createdAt', 'expire', 'providerAccessTokenExpiry']); + $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']); @@ -77,12 +163,16 @@ class V15 extends Filter break; } - // Downgrade Permissions for all models - $parsedResponse = $this->parsePermissions($parsedResponse); - return $parsedResponse; } + protected function parseBuild(array $content) + { + $content = $this->parseDatetimeAttributes($content, ['startTime', 'endTime']); + + return $content; + } + protected function parseBucket(array $content) { if (isset($content['fileSecurity'])) { @@ -96,6 +186,7 @@ class V15 extends Filter unset($content['fileSecurity']); unset($content['compression']); + $content = $this->parsePermissions($content); $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); return $content; @@ -196,6 +287,14 @@ class V15 extends Filter } 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; } @@ -203,10 +302,17 @@ class V15 extends Filter private function parseExecution($content) { unset($content['stdout']); + $content = $this->parsePermissions($content); $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'startTime', 'endTime']); return $content; } + private function parseCreatedAtUpdatedAt($content) + { + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt']); + return $content; + } + private function parseFunction($content) { if (isset($content['execute'])) { @@ -227,6 +333,30 @@ class V15 extends Filter return $content; } + private function parseKey($content) + { + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'expire']); + return $content; + } + + private function parseLog($content) + { + $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', '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 parseModelUsageFunc($content) { $mapping = [ diff --git a/tests/unit/Utopia/Response/Filters/V15Test.php b/tests/unit/Utopia/Response/Filters/V15Test.php index 48754e8dca..092fe0b5c6 100644 --- a/tests/unit/Utopia/Response/Filters/V15Test.php +++ b/tests/unit/Utopia/Response/Filters/V15Test.php @@ -7,6 +7,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Permission; use Utopia\Database\Role; use PHPUnit\Framework\TestCase; +use stdClass; class V15Test extends TestCase { @@ -240,6 +241,49 @@ class V15Test extends TestCase $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; @@ -259,6 +303,28 @@ class V15Test extends TestCase $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 [ @@ -344,6 +410,30 @@ class V15Test extends TestCase $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 */ @@ -356,6 +446,28 @@ class V15Test extends TestCase $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 */ @@ -368,6 +480,28 @@ class V15Test extends TestCase $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); + } + /** * @dataProvider createdAtUpdatedAtProvider * @dataProvider permissionsProvider @@ -381,6 +515,29 @@ class V15Test extends TestCase $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 */ @@ -393,6 +550,28 @@ class V15Test extends TestCase $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 [ @@ -417,6 +596,30 @@ class V15Test extends TestCase $this->assertEquals($expected, $result); } + /** + * @dataProvider createdAtUpdatedAtProvider + * @dataProvider permissionsProvider + * @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 @@ -430,6 +633,29 @@ class V15Test extends TestCase $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 [ @@ -502,6 +728,29 @@ class V15Test extends TestCase $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 [ @@ -525,6 +774,29 @@ class V15Test extends TestCase $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 [ @@ -548,6 +820,29 @@ class V15Test extends TestCase $this->assertEquals($expected, $result); } + /** + * @dataProvider createdAtUpdatedAtProvider + * @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 [ @@ -577,6 +872,29 @@ class V15Test extends TestCase $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 [ @@ -615,6 +933,28 @@ class V15Test extends TestCase $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 */ @@ -627,6 +967,28 @@ class V15Test extends TestCase $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 [ @@ -657,6 +1019,28 @@ class V15Test extends TestCase $this->assertEquals($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 */ @@ -669,6 +1053,28 @@ class V15Test extends TestCase $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 [ @@ -909,4 +1315,117 @@ class V15Test extends TestCase $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); + } } From 1d7c25354a88e99bcfab65a88df0b4c3656bd867 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 12 Sep 2022 22:15:13 +0000 Subject: [PATCH 12/17] Update response filters for usage --- src/Appwrite/Utopia/Response/Filters/V15.php | 146 ++++++- .../unit/Utopia/Response/Filters/V15Test.php | 384 ++++++++++++++++++ 2 files changed, 512 insertions(+), 18 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 047eb1d268..c927dd8605 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -152,8 +152,23 @@ class V15 extends Filter 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->parseModelUsageFunc($parsedResponse); + $parsedResponse = $this->parseUsageFuncs($parsedResponse); break; case Response::MODEL_USAGE_PROJECT: $parsedResponse = $this->parseUsageProject($parsedResponse); @@ -357,7 +372,114 @@ class V15 extends Filter return $content; } - private function parseModelUsageFunc($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', @@ -393,7 +515,7 @@ class V15 extends Filter $content['functions'] = $content['executions']; unset($content['executions']); - $usage = [ + $keys = [ 'collections', 'documents', 'functions', @@ -403,13 +525,7 @@ class V15 extends Filter 'users', ]; - foreach ($usage as $name) { - $data = []; - foreach ($content[$name] as $metric) { - $data[] = $this->parseMetric($metric); - } - $content[$name] = $data; - } + $content = $this->parseUsage($content, $keys); return $content; } @@ -419,7 +535,7 @@ class V15 extends Filter $content['filesStorage'] = $content['storage']; unset($content['storage']); - $usage = [ + $keys = [ 'bucketsCount', 'bucketsCreate', 'bucketsDelete', @@ -433,13 +549,7 @@ class V15 extends Filter 'filesUpdate', ]; - foreach ($usage as $name) { - $data = []; - foreach ($content[$name] as $metric) { - $data[] = $this->parseMetric($metric); - } - $content[$name] = $data; - } + $content = $this->parseUsage($content, $keys); return $content; } diff --git a/tests/unit/Utopia/Response/Filters/V15Test.php b/tests/unit/Utopia/Response/Filters/V15Test.php index 092fe0b5c6..dbec42c341 100644 --- a/tests/unit/Utopia/Response/Filters/V15Test.php +++ b/tests/unit/Utopia/Response/Filters/V15Test.php @@ -1103,6 +1103,390 @@ class V15Test extends TestCase $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 [ From eca5aa3c2bba4b624752befe76af96b3fee8ea4d Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 20:42:45 +0000 Subject: [PATCH 13/17] Fix version matching for 0.15.X request & response --- app/controllers/general.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index 09a0415f90..e56357869d 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -70,7 +70,7 @@ App::init() case version_compare($requestFormat, '0.14.0', '<'): Request::setFilter(new RequestV14()); break; - case version_compare($requestFormat, '0.15.0', '<'): + case version_compare($requestFormat, '0.15.3', '<'): Request::setFilter(new RequestV15()); break; default: @@ -199,7 +199,7 @@ App::init() case version_compare($responseFormat, '0.14.0', '<='): Response::setFilter(new ResponseV14()); break; - case version_compare($responseFormat, '0.15.0', '<='): + case version_compare($responseFormat, '0.15.3', '<='): Response::setFilter(new ResponseV15()); break; default: From 717abccd10a334cd259e85cf0024ca2a0585c064 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 20:43:46 +0000 Subject: [PATCH 14/17] Fix V15 response format for functions and executions --- src/Appwrite/Utopia/Response/Filters/V15.php | 25 ++++++++++- .../unit/Utopia/Response/Filters/V15Test.php | 41 ++++++++++++++++--- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index c927dd8605..8c56e65e2a 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -317,8 +317,23 @@ class V15 extends Filter private function parseExecution($content) { unset($content['stdout']); - $content = $this->parsePermissions($content); - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'startTime', 'endTime']); + + 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; } @@ -344,7 +359,13 @@ class V15 extends Filter $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; } diff --git a/tests/unit/Utopia/Response/Filters/V15Test.php b/tests/unit/Utopia/Response/Filters/V15Test.php index dbec42c341..8998c759b1 100644 --- a/tests/unit/Utopia/Response/Filters/V15Test.php +++ b/tests/unit/Utopia/Response/Filters/V15Test.php @@ -576,15 +576,43 @@ class V15Test extends TestCase { return [ 'basic execution' => [ - ['stdout' => ''], - [], + [ + '$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 permissionsProvider * @dataProvider executionProvider */ public function testExecution(array $content, array $expected): void @@ -598,7 +626,6 @@ class V15Test extends TestCase /** * @dataProvider createdAtUpdatedAtProvider - * @dataProvider permissionsProvider * @dataProvider executionProvider */ public function testExecutionList(array $content, array $expected): void @@ -668,7 +695,7 @@ class V15Test extends TestCase Role::users()->toString(), ], 'name' => 'My Function', - 'status' => 'enabled', + 'enabled' => true, 'runtime' => 'python-3.8', 'deployment' => '5e5ea5c16897e', 'vars' => [ @@ -712,6 +739,10 @@ class V15Test extends TestCase 'timeout' => 1592981237 ], ], + 'enabled false' => [ + ['enabled' => false], + ['status' => 'disabled'], + ], ]; } From 8f67743834de28659c98e661578b6bc7ae5a12cc Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 20:46:32 +0000 Subject: [PATCH 15/17] Rename teams.getMemberships to teams.listMemberships in V15 request filter --- src/Appwrite/Utopia/Request/Filters/V15.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index d9e6df8be3..7badac23b7 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -33,7 +33,7 @@ class V15 extends Filter case 'storage.listBuckets': case 'storage.listFiles': case 'teams.list': - case 'teams.getMemberships': + case 'teams.listMemberships': case 'users.list': $content = $this->convertLimitAndOffset($content); $content = $this->convertCursor($content); From 2da7da0558bcdbab9855a926aba7ce2fd1b0d2bb Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 21:18:13 +0000 Subject: [PATCH 16/17] Remove response parse of log $createdAt and $updatedAt --- src/Appwrite/Utopia/Response/Filters/V15.php | 2 +- .../unit/Utopia/Response/Filters/V15Test.php | 50 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Filters/V15.php b/src/Appwrite/Utopia/Response/Filters/V15.php index 8c56e65e2a..8e688d58ff 100644 --- a/src/Appwrite/Utopia/Response/Filters/V15.php +++ b/src/Appwrite/Utopia/Response/Filters/V15.php @@ -377,7 +377,7 @@ class V15 extends Filter private function parseLog($content) { - $content = $this->parseDatetimeAttributes($content, ['$createdAt', '$updatedAt', 'time']); + $content = $this->parseDatetimeAttributes($content, ['time']); return $content; } diff --git a/tests/unit/Utopia/Response/Filters/V15Test.php b/tests/unit/Utopia/Response/Filters/V15Test.php index 8998c759b1..a68da474d9 100644 --- a/tests/unit/Utopia/Response/Filters/V15Test.php +++ b/tests/unit/Utopia/Response/Filters/V15Test.php @@ -832,14 +832,57 @@ class V15Test extends TestCase { return [ 'basic log' => [ - ['time' => '2020-06-24T06:47:30.000Z'], - ['time' => 1592981250], + [ + '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 createdAtUpdatedAtProvider * @dataProvider logProvider */ public function testLog(array $content, array $expected): void @@ -852,7 +895,6 @@ class V15Test extends TestCase } /** - * @dataProvider createdAtUpdatedAtProvider * @dataProvider logProvider */ public function testLogList(array $content, array $expected): void From 041066520f455e5ce728750919fd879a18a8401d Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 21:28:23 +0000 Subject: [PATCH 17/17] Fix some sdk methods for V15 request filter --- src/Appwrite/Utopia/Request/Filters/V15.php | 4 ++-- tests/unit/Utopia/Request/Filters/V15Test.php | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/Utopia/Request/Filters/V15.php b/src/Appwrite/Utopia/Request/Filters/V15.php index 7badac23b7..65b09e1f24 100644 --- a/src/Appwrite/Utopia/Request/Filters/V15.php +++ b/src/Appwrite/Utopia/Request/Filters/V15.php @@ -14,12 +14,12 @@ class V15 extends Filter public function parse(array $content, string $model): array { switch ($model) { - case 'account.logs': + case 'account.listLogs': case 'databases.listLogs': case 'databases.listCollectionLogs': case 'databases.listDocumentLogs': case 'teams.listLogs': - case 'users.getLogs': + case 'users.listLogs': $content = $this->convertLimitAndOffset($content); break; case 'account.initials': diff --git a/tests/unit/Utopia/Request/Filters/V15Test.php b/tests/unit/Utopia/Request/Filters/V15Test.php index 1617c2b0c5..70bf71d4cb 100644 --- a/tests/unit/Utopia/Request/Filters/V15Test.php +++ b/tests/unit/Utopia/Request/Filters/V15Test.php @@ -36,9 +36,9 @@ class V15Test extends TestCase /** * @dataProvider limitOffsetProvider */ - public function testGetAccountLogs(array $content, array $expected): void + public function testListAccountLogs(array $content, array $expected): void { - $model = 'account.logs'; + $model = 'account.listLogs'; $result = $this->filter->parse($content, $model); @@ -692,9 +692,9 @@ class V15Test extends TestCase * @dataProvider cursorProvider * @dataProvider orderTypeProvider */ - public function testGetTeamMemberships(array $content, array $expected): void + public function testListTeamMemberships(array $content, array $expected): void { - $model = 'teams.getMemberships'; + $model = 'teams.listMemberships'; $result = $this->filter->parse($content, $model); @@ -731,9 +731,9 @@ class V15Test extends TestCase /** * @dataProvider limitOffsetProvider */ - public function testGetUserLogs(array $content, array $expected): void + public function testListUserLogs(array $content, array $expected): void { - $model = 'users.getLogs'; + $model = 'users.listLogs'; $result = $this->filter->parse($content, $model);