From e1cc6bc6249195f96a1f8f1092d650b2a8eee91c Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 15 Aug 2022 16:09:09 +0100 Subject: [PATCH 01/52] 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/52] 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/52] 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 8e1dc84a48a3305dd006626b8d0e0641664aff07 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 10:32:56 +0300 Subject: [PATCH 04/52] account labels --- app/controllers/api/account.php | 21 +++++++++++++++++++++ app/controllers/shared/api.php | 2 ++ 2 files changed, 23 insertions(+) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 1309eade74..c9c69e6368 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -53,6 +53,7 @@ App::post('/v1/account') ->label('event', 'users.[userId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') + ->label('audits.event', 'account.create') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') @@ -145,6 +146,7 @@ App::post('/v1/account/sessions/email') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') + ->label('audits.event', 'account.session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -604,6 +606,7 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') + ->label('audits.event', 'account.session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) @@ -736,6 +739,7 @@ App::put('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') + ->label('audits.event', 'account.session.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -855,6 +859,7 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') + ->label('audits.event', 'account.session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) @@ -1088,6 +1093,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') + ->label('audits.event', 'account.session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -1442,6 +1448,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') + ->label('audits.event', 'account.name.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1472,6 +1479,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') + ->label('audits.event', 'account.password.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -1511,6 +1519,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') + ->label('audits.event', 'account.email.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1562,6 +1571,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') + ->label('audits.event', 'account.phone.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1609,6 +1619,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') + ->label('audits.event', 'account.preferences.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1637,6 +1648,7 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') + ->label('audits.event', 'account.status.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1671,6 +1683,7 @@ App::delete('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') + ->label('audits.event', 'account.session.delete') ->label('audits.resource', 'user/{user.$id}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1741,6 +1754,7 @@ App::patch('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') + ->label('audits.event', 'account.session.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.update') @@ -1822,6 +1836,7 @@ App::delete('/v1/account/sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') + ->label('audits.event', 'account.sessions.delete') ->label('audits.resource', 'user/{user.$id}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1883,6 +1898,7 @@ App::post('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].create') + ->label('audits.event', 'account.recovery.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -1988,6 +2004,7 @@ App::put('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') + ->label('audits.event', 'account.recovery.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -2056,6 +2073,7 @@ App::post('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') + ->label('audits.event', 'account.verification.create') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -2144,6 +2162,7 @@ App::put('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') + ->label('audits.event', 'account.verification.update') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -2202,6 +2221,7 @@ App::post('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') + ->label('audits.event', 'account.verification.create') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -2285,6 +2305,7 @@ App::put('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') + ->label('audits.event', 'account.verification.update') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 93bc020d97..7d9fa2509f 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -342,6 +342,8 @@ App::shutdown() $audits->setPayload($responsePayload); } + $audits->setEvent($route->getLabel('audits.event', '')); + foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } From 5d16c39d5fc4a458a18f195c19ccaa30fa70eb4b Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 11:13:44 +0300 Subject: [PATCH 05/52] account labels --- app/controllers/api/databases.php | 21 +++++++++++++++++++++ app/controllers/api/functions.php | 13 +++++++++++++ app/controllers/api/storage.php | 6 ++++++ app/controllers/api/teams.php | 7 +++++++ app/controllers/api/users.php | 19 +++++++++++++++++++ 5 files changed, 66 insertions(+) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 3167287b1e..7b1f1f29bf 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -153,6 +153,7 @@ App::post('/v1/databases') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].create') ->label('scope', 'databases.write') + ->label('audits.event', 'databases.create') ->label('audits.resource', 'database/{response.$id}') ->label('usage.metric', 'databases.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -385,6 +386,7 @@ App::put('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].update') + ->label('audits.event', 'databases.update') ->label('audits.resource', 'database/{response.$id}') ->label('usage.metric', 'databases.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -427,6 +429,7 @@ App::delete('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].delete') + ->label('audits.event', 'databases.delete') ->label('audits.resource', 'database/{request.databaseId}') ->label('usage.metric', 'databases.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -473,6 +476,7 @@ App::post('/v1/databases/:databaseId/collections') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{response.$id}') ->label('usage.metric', 'collections.{scope}.requests.create') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -726,6 +730,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].update') + ->label('audits.event', 'databases.collections.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -793,6 +798,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].delete') + ->label('audits.event', 'databases.collections.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.delete') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -849,6 +855,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.string.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -897,6 +904,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.email.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -939,6 +947,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.enum.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -997,6 +1006,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.ip.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1039,6 +1049,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.url.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1081,6 +1092,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.integer.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1152,6 +1164,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.float.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1226,6 +1239,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.boolean.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1268,6 +1282,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.attributes.datetime.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1421,6 +1436,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete') + ->label('audits.event', 'databases.collections.attributes.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1508,6 +1524,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create') ->label('scope', 'collections.write') + ->label('audits.event', 'databases.collections.indexes.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1743,6 +1760,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete') + ->label('audits.event', 'databases.collections.indexes.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1810,6 +1828,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') + ->label('audits.event', 'databases.collections.documents.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'documents.{scope}.requests.create') ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) @@ -2190,6 +2209,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update') ->label('scope', 'documents.write') + ->label('audits.event', 'databases.collections.documents.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}') ->label('usage.metric', 'documents.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) @@ -2322,6 +2342,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->groups(['api', 'database']) ->label('scope', 'documents.write') ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].delete') + ->label('audits.event', 'databases.collections.documents.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{request.documentId}') ->label('usage.metric', 'documents.{scope}.requests.delete') ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index eb7dbdad54..ddab426dc5 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -52,6 +52,7 @@ App::post('/v1/functions') ->desc('Create Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].create') + ->label('audits.event', 'functions.create') ->label('audits.resource', 'function/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -409,6 +410,7 @@ App::put('/v1/functions/:functionId') ->desc('Update Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].update') + ->label('audits.event', 'functions.update') ->label('audits.resource', 'function/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -471,6 +473,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Update Function Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') + ->label('audits.event', 'functions.deployments.update') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -537,6 +540,7 @@ App::delete('/v1/functions/:functionId') ->desc('Delete Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].delete') + ->label('audits.event', 'functions.delete') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -575,6 +579,7 @@ App::post('/v1/functions/:functionId/deployments') ->desc('Create Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].create') + ->label('audits.event', 'functions.deployments.create') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -866,6 +871,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Delete Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].delete') + ->label('audits.event', 'functions.deployments.delete') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -1237,6 +1243,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->desc('Retry Build') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') + ->label('audits.event', 'functions.deployments.builds.create') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'functions') @@ -1296,6 +1303,8 @@ App::post('/v1/functions/:functionId/variables') ->desc('Create Variable') ->groups(['api', 'functions']) ->label('scope', 'functions.write') + ->label('audits.event', 'functions.variables.create') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'createVariable') @@ -1433,6 +1442,8 @@ App::put('/v1/functions/:functionId/variables/:variableId') ->desc('Update Variable') ->groups(['api', 'functions']) ->label('scope', 'functions.write') + ->label('audits.event', 'functions.variables.update') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'updateVariable') @@ -1484,6 +1495,8 @@ App::delete('/v1/functions/:functionId/variables/:variableId') ->desc('Delete Variable') ->groups(['api', 'functions']) ->label('scope', 'functions.write') + ->label('audits.event', 'functions.variables.delete') + ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') ->label('sdk.method', 'deleteVariable') diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 2fe9a941a9..9040f10002 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -48,6 +48,7 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') + ->label('audits.event', 'buckets.create') ->label('audits.resource', 'buckets/{response.$id}') ->label('usage.metric', 'buckets.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -218,6 +219,7 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') + ->label('audits.event', 'buckets.update') ->label('audits.resource', 'buckets/{response.$id}') ->label('usage.metric', 'buckets.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -283,6 +285,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->desc('Delete Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') + ->label('audits.event', 'buckets.delete') ->label('event', 'buckets.[bucketId].delete') ->label('audits.resource', 'buckets/{request.bucketId}') ->label('usage.metric', 'buckets.{scope}.requests.delete') @@ -325,6 +328,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->desc('Create File') ->groups(['api', 'storage']) ->label('scope', 'files.write') + ->label('audits.event', 'files.create') ->label('event', 'buckets.[bucketId].files.[fileId].create') ->label('audits.resource', 'files/{response.$id}') ->label('usage.metric', 'files.{scope}.requests.create') @@ -1236,6 +1240,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') + ->label('audits.event', 'files.update') ->label('audits.resource', 'files/{response.$id}') ->label('usage.metric', 'files.{scope}.requests.update') ->label('usage.params', ['bucketId:{request.bucketId}']) @@ -1338,6 +1343,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') + ->label('audits.event', 'files.delete') ->label('audits.resource', 'file/{request.fileId}') ->label('usage.metric', 'files.{scope}.requests.delete') ->label('usage.params', ['bucketId:{request.bucketId}']) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 40eab55630..ecb6894627 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -45,6 +45,7 @@ App::post('/v1/teams') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].create') ->label('scope', 'teams.write') + ->label('audits.event', 'teams.create') ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -199,6 +200,7 @@ App::put('/v1/teams/:teamId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].update') ->label('scope', 'teams.write') + ->label('audits.event', 'teams.update') ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -234,6 +236,7 @@ App::delete('/v1/teams/:teamId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].delete') ->label('scope', 'teams.write') + ->label('audits.event', 'teams.delete') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -288,6 +291,7 @@ App::post('/v1/teams/:teamId/memberships') ->label('event', 'teams.[teamId].memberships.[membershipId].create') ->label('scope', 'teams.write') ->label('auth.type', 'invites') + ->label('audits.event', 'teams.memberships.create') ->label('audits.resource', 'team/{request.teamId}') ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) @@ -582,6 +586,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update') ->label('scope', 'teams.write') + ->label('audits.event', 'teams.memberships.update') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -652,6 +657,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update.status') ->label('scope', 'public') + ->label('audits.event', 'teams.memberships.status.update') ->label('audits.resource', 'team/{request.teamId}') ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -785,6 +791,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].delete') ->label('scope', 'teams.write') + ->label('audits.event', 'teams.memberships.delete') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 9f4b1489e8..5d9fff4cb7 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -88,6 +88,7 @@ App::post('/v1/users') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -117,6 +118,7 @@ App::post('/v1/users/bcrypt') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.bcrypt') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -145,6 +147,7 @@ App::post('/v1/users/md5') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.md5') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -173,6 +176,7 @@ App::post('/v1/users/argon2') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.argon2') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -201,6 +205,7 @@ App::post('/v1/users/sha') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.sha') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -236,6 +241,7 @@ App::post('/v1/users/phpass') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.phpass') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -264,6 +270,7 @@ App::post('/v1/users/scrypt') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.scrypt') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -305,6 +312,7 @@ App::post('/v1/users/scrypt-modified') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') + ->label('audits.event', 'users.create.scrypt-modified') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -601,6 +609,7 @@ App::patch('/v1/users/:userId/status') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.status') ->label('scope', 'users.write') + ->label('audits.event', 'users.status.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -637,6 +646,7 @@ App::patch('/v1/users/:userId/verification') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') + ->label('audits.event', 'users.verification.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -672,6 +682,7 @@ App::patch('/v1/users/:userId/verification/phone') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') + ->label('audits.event', 'users.verification.phone.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -707,6 +718,7 @@ App::patch('/v1/users/:userId/name') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.name') ->label('scope', 'users.write') + ->label('audits.event', 'users.name.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -747,6 +759,7 @@ App::patch('/v1/users/:userId/password') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.password') ->label('scope', 'users.write') + ->label('audits.event', 'users.password.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -788,6 +801,7 @@ App::patch('/v1/users/:userId/email') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.email') ->label('scope', 'users.write') + ->label('audits.event', 'users.email.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -834,6 +848,7 @@ App::patch('/v1/users/:userId/phone') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'users.write') + ->label('audits.event', 'users.phone.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -878,6 +893,7 @@ App::patch('/v1/users/:userId/verification') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') + ->label('audits.event', 'users.verification.email.update') ->label('audits.resource', 'user/{request.userId}') ->label('audits.userId', '{request.userId}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -947,6 +963,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->groups(['api', 'users']) ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('scope', 'users.write') + ->label('audits.event', 'users.session.delete') ->label('audits.resource', 'user/{request.userId}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -989,6 +1006,7 @@ App::delete('/v1/users/:userId/sessions') ->groups(['api', 'users']) ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('scope', 'users.write') + ->label('audits.event', 'users.sessions.delete') ->label('audits.resource', 'user/{user.$id}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1031,6 +1049,7 @@ App::delete('/v1/users/:userId') ->groups(['api', 'users']) ->label('event', 'users.[userId].delete') ->label('scope', 'users.write') + ->label('audits.event', 'users.delete') ->label('audits.resource', 'user/{request.userId}') ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) From 5ea081654090474ccaa2ba31aa950debb3d2d0c7 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 11:17:53 +0300 Subject: [PATCH 06/52] account labels --- app/controllers/shared/api.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 7d9fa2509f..d36fd90131 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -144,7 +144,7 @@ App::init() ->setMode($mode) ->setUserAgent($request->getUserAgent('')) ->setIP($request->getIP()) - ->setEvent($route->getLabel('event', '')) + ->setEvent($route->getLabel('audit.event', '')) ->setProject($project) ->setUser($user); @@ -342,8 +342,6 @@ App::shutdown() $audits->setPayload($responsePayload); } - $audits->setEvent($route->getLabel('audits.event', '')); - foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } From 2c9b749f72931e055d1bef9700198122aa96a76a Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 11:23:24 +0300 Subject: [PATCH 07/52] account labels --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index d36fd90131..e07f405140 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -144,7 +144,7 @@ App::init() ->setMode($mode) ->setUserAgent($request->getUserAgent('')) ->setIP($request->getIP()) - ->setEvent($route->getLabel('audit.event', '')) + ->setEvent($route->getLabel('audits.event', '')) ->setProject($project) ->setUser($user); From f63c740917dcb831618c6c11f3a74c43c405a6b2 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 11:45:53 +0300 Subject: [PATCH 08/52] decouple audits log from events --- app/controllers/shared/api.php | 2 ++ app/workers/audits.php | 4 ++-- src/Appwrite/Event/Audit.php | 25 ++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index e07f405140..7d9b3fe4d9 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -342,6 +342,8 @@ App::shutdown() $audits->setPayload($responsePayload); } + var_dump($audits); + foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } diff --git a/app/workers/audits.php b/app/workers/audits.php index 696eb6df50..b86649543b 100644 --- a/app/workers/audits.php +++ b/app/workers/audits.php @@ -24,7 +24,7 @@ class AuditsV1 extends Worker public function run(): void { - $events = $this->args['events']; + $event = $this->args['event']; $payload = $this->args['payload']; $mode = $this->args['mode']; $resource = $this->args['resource']; @@ -42,7 +42,7 @@ class AuditsV1 extends Worker $audit->log( userId: $user->getId(), // Pass first, most verbose event pattern - event: $events[0], + event: $event, resource: $resource, userAgent: $userAgent, ip: $ip, diff --git a/src/Appwrite/Event/Audit.php b/src/Appwrite/Event/Audit.php index 4df3eeec62..2020548969 100644 --- a/src/Appwrite/Event/Audit.php +++ b/src/Appwrite/Event/Audit.php @@ -108,6 +108,29 @@ class Audit extends Event return $this->ip; } + /** + * Set description for this audit event + * + * @param string $event + * @return self + */ + public function setEvent(string $event): self + { + $this->event = $event; + + return $this; + } + + /** + * Returns the audit event description. + * + * @return string + */ + public function getEvent(): string + { + return $this->event; + } + /** * Executes the event and sends it to the audit worker. * @@ -124,7 +147,7 @@ class Audit extends Event 'mode' => $this->mode, 'ip' => $this->ip, 'userAgent' => $this->userAgent, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) + 'event' => $this->event, ]); } } From db715f3e7dc6a354e22419977ac2d2f3bf77b979 Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 13:31:38 +0300 Subject: [PATCH 09/52] decouple audits log from events --- app/controllers/api/account.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index c9c69e6368..490650a41e 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -146,7 +146,7 @@ App::post('/v1/account/sessions/email') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') - ->label('audits.event', 'account.session.create') + ->label('audits.event', 'account.session.email.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -606,7 +606,7 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') - ->label('audits.event', 'account.session.create') + ->label('audits.event', 'account.session.magic-url.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) @@ -859,7 +859,7 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') - ->label('audits.event', 'account.session.create') + ->label('audits.event', 'account.session.phone.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) @@ -1093,7 +1093,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') - ->label('audits.event', 'account.session.create') + ->label('audits.event', 'account.session.anonymous.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') From eabc90ec497e46aeb92a4a9bd4e4190aa29eb15b Mon Sep 17 00:00:00 2001 From: shimon Date: Sun, 4 Sep 2022 17:53:37 +0300 Subject: [PATCH 10/52] decouple audits log from events --- app/controllers/shared/api.php | 2 -- tests/e2e/Services/Account/AccountBase.php | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 7d9b3fe4d9..e07f405140 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -342,8 +342,6 @@ App::shutdown() $audits->setPayload($responsePayload); } - var_dump($audits); - foreach ($events->getParams() as $key => $value) { $audits->setParam($key, $value); } diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 90254a1489..37c4277e85 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -341,7 +341,7 @@ trait AccountBase $this->assertNotEmpty($response['body']['logs']); $this->assertCount(3, $response['body']['logs']); $this->assertIsNumeric($response['body']['total']); - $this->assertContains($response['body']['logs'][1]['event'], ["users.{$userId}.create", "users.{$userId}.sessions.{$sessionId}.create"]); + $this->assertContains($response['body']['logs'][1]['event'], ["account.session.email.create"]); $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, DateTime::isValid($response['body']['logs'][1]['time'])); @@ -363,7 +363,7 @@ trait AccountBase $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); - $this->assertContains($response['body']['logs'][2]['event'], ["users.{$userId}.create", "users.{$userId}.sessions.{$sessionId}.create"]); + $this->assertContains($response['body']['logs'][2]['event'], ["account.create"]); $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, DateTime::isValid($response['body']['logs'][2]['time'])); From 13629020823bf9e8a4f8bc48e2bc6d77719574de Mon Sep 17 00:00:00 2001 From: shimon Date: Mon, 5 Sep 2022 11:00:08 +0300 Subject: [PATCH 11/52] audit event name reformation --- app/controllers/api/account.php | 41 ++++++++++----------- app/controllers/api/databases.php | 42 +++++++++++----------- app/controllers/api/functions.php | 20 +++++------ app/controllers/api/storage.php | 12 +++---- app/controllers/api/teams.php | 14 ++++---- app/controllers/api/users.php | 38 ++++++++++---------- tests/e2e/Services/Account/AccountBase.php | 2 +- 7 files changed, 85 insertions(+), 84 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 490650a41e..6683a3d828 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -146,7 +146,7 @@ App::post('/v1/account/sessions/email') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') - ->label('audits.event', 'account.session.email.create') + ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -368,6 +368,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') + ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{user.$id}') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') @@ -606,7 +607,7 @@ App::post('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'magic-url') - ->label('audits.event', 'account.session.magic-url.create') + ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) @@ -739,7 +740,7 @@ App::put('/v1/account/sessions/magic-url') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].sessions.[sessionId].create') - ->label('audits.event', 'account.session.update') + ->label('audits.event', 'session.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -859,7 +860,7 @@ App::post('/v1/account/sessions/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('auth.type', 'phone') - ->label('audits.event', 'account.session.phone.create') + ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('sdk.auth', []) @@ -1093,7 +1094,7 @@ App::post('/v1/account/sessions/anonymous') ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') ->label('auth.type', 'anonymous') - ->label('audits.event', 'account.session.anonymous.create') + ->label('audits.event', 'session.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.create') @@ -1448,7 +1449,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') - ->label('audits.event', 'account.name.update') + ->label('audits.event', 'account.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1479,7 +1480,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') - ->label('audits.event', 'account.password.update') + ->label('audits.event', 'account.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -1519,7 +1520,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') - ->label('audits.event', 'account.email.update') + ->label('audits.event', 'account.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1571,7 +1572,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') - ->label('audits.event', 'account.phone.update') + ->label('audits.event', 'account.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1619,7 +1620,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') - ->label('audits.event', 'account.preferences.update') + ->label('audits.event', 'account.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1648,7 +1649,7 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') - ->label('audits.event', 'account.status.update') + ->label('audits.event', 'account.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1683,7 +1684,7 @@ App::delete('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') - ->label('audits.event', 'account.session.delete') + ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{user.$id}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1754,7 +1755,7 @@ App::patch('/v1/account/sessions/:sessionId') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') - ->label('audits.event', 'account.session.update') + ->label('audits.event', 'session.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'sessions.{scope}.requests.update') @@ -1836,7 +1837,7 @@ App::delete('/v1/account/sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') - ->label('audits.event', 'account.sessions.delete') + ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{user.$id}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1898,7 +1899,7 @@ App::post('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].create') - ->label('audits.event', 'account.recovery.create') + ->label('audits.event', 'recovery.create') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -2004,7 +2005,7 @@ App::put('/v1/account/recovery') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].recovery.[tokenId].update') - ->label('audits.event', 'account.recovery.update') + ->label('audits.event', 'recovery.update') ->label('audits.resource', 'user/{response.userId}') ->label('audits.userId', '{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -2073,7 +2074,7 @@ App::post('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.event', 'account.verification.create') + ->label('audits.event', 'verification.create') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -2162,7 +2163,7 @@ App::put('/v1/account/verification') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.event', 'account.verification.update') + ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -2221,7 +2222,7 @@ App::post('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].verification.[tokenId].create') - ->label('audits.event', 'account.verification.create') + ->label('audits.event', 'verification.create') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -2305,7 +2306,7 @@ App::put('/v1/account/verification/phone') ->groups(['api', 'account']) ->label('scope', 'public') ->label('event', 'users.[userId].verification.[tokenId].update') - ->label('audits.event', 'account.verification.update') + ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.userId}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 7b1f1f29bf..28b822a953 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -153,7 +153,7 @@ App::post('/v1/databases') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].create') ->label('scope', 'databases.write') - ->label('audits.event', 'databases.create') + ->label('audits.event', 'database.create') ->label('audits.resource', 'database/{response.$id}') ->label('usage.metric', 'databases.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -386,7 +386,7 @@ App::put('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].update') - ->label('audits.event', 'databases.update') + ->label('audits.event', 'database.update') ->label('audits.resource', 'database/{response.$id}') ->label('usage.metric', 'databases.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -429,7 +429,7 @@ App::delete('/v1/databases/:databaseId') ->groups(['api', 'database']) ->label('scope', 'databases.write') ->label('event', 'databases.[databaseId].delete') - ->label('audits.event', 'databases.delete') + ->label('audits.event', 'database.delete') ->label('audits.resource', 'database/{request.databaseId}') ->label('usage.metric', 'databases.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -476,7 +476,7 @@ App::post('/v1/databases/:databaseId/collections') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.create') + ->label('audits.event', 'collection.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{response.$id}') ->label('usage.metric', 'collections.{scope}.requests.create') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -730,7 +730,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].update') - ->label('audits.event', 'databases.collections.update') + ->label('audits.event', 'collection.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -798,7 +798,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].delete') - ->label('audits.event', 'databases.collections.delete') + ->label('audits.event', 'collection.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.delete') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -855,7 +855,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.string.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -904,7 +904,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.email.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -947,7 +947,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.enum.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1006,7 +1006,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.ip.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1049,7 +1049,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.url.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1092,7 +1092,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.integer.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1164,7 +1164,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.float.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1239,7 +1239,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.boolean.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1282,7 +1282,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.attributes.datetime.create') + ->label('audits.event', 'attribute.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1436,7 +1436,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete') - ->label('audits.event', 'databases.collections.attributes.delete') + ->label('audits.event', 'attribute.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1524,7 +1524,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create') ->label('scope', 'collections.write') - ->label('audits.event', 'databases.collections.indexes.create') + ->label('audits.event', 'index.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1760,7 +1760,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->groups(['api', 'database']) ->label('scope', 'collections.write') ->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete') - ->label('audits.event', 'databases.collections.indexes.delete') + ->label('audits.event', 'index.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'collections.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}']) @@ -1828,7 +1828,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create') ->label('scope', 'documents.write') - ->label('audits.event', 'databases.collections.documents.create') + ->label('audits.event', 'document.create') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') ->label('usage.metric', 'documents.{scope}.requests.create') ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) @@ -2209,7 +2209,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ->groups(['api', 'database']) ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update') ->label('scope', 'documents.write') - ->label('audits.event', 'databases.collections.documents.update') + ->label('audits.event', 'document.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}') ->label('usage.metric', 'documents.{scope}.requests.update') ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) @@ -2342,7 +2342,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->groups(['api', 'database']) ->label('scope', 'documents.write') ->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].delete') - ->label('audits.event', 'databases.collections.documents.delete') + ->label('audits.event', 'document.delete') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{request.documentId}') ->label('usage.metric', 'documents.{scope}.requests.delete') ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index ddab426dc5..72c6580a13 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -52,7 +52,7 @@ App::post('/v1/functions') ->desc('Create Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].create') - ->label('audits.event', 'functions.create') + ->label('audits.event', 'function.create') ->label('audits.resource', 'function/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -410,7 +410,7 @@ App::put('/v1/functions/:functionId') ->desc('Update Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].update') - ->label('audits.event', 'functions.update') + ->label('audits.event', 'function.update') ->label('audits.resource', 'function/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -473,7 +473,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Update Function Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') - ->label('audits.event', 'functions.deployments.update') + ->label('audits.event', 'deployment.update') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -540,7 +540,7 @@ App::delete('/v1/functions/:functionId') ->desc('Delete Function') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].delete') - ->label('audits.event', 'functions.delete') + ->label('audits.event', 'function.delete') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -579,7 +579,7 @@ App::post('/v1/functions/:functionId/deployments') ->desc('Create Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].create') - ->label('audits.event', 'functions.deployments.create') + ->label('audits.event', 'deployment.create') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -871,7 +871,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') ->desc('Delete Deployment') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].delete') - ->label('audits.event', 'functions.deployments.delete') + ->label('audits.event', 'deployment.delete') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -1243,7 +1243,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->desc('Retry Build') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') - ->label('audits.event', 'functions.deployments.builds.create') + ->label('audits.event', 'build.create') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'functions') @@ -1303,7 +1303,7 @@ App::post('/v1/functions/:functionId/variables') ->desc('Create Variable') ->groups(['api', 'functions']) ->label('scope', 'functions.write') - ->label('audits.event', 'functions.variables.create') + ->label('audits.event', 'variable.create') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -1442,7 +1442,7 @@ App::put('/v1/functions/:functionId/variables/:variableId') ->desc('Update Variable') ->groups(['api', 'functions']) ->label('scope', 'functions.write') - ->label('audits.event', 'functions.variables.update') + ->label('audits.event', 'variable.update') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') @@ -1495,7 +1495,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId') ->desc('Delete Variable') ->groups(['api', 'functions']) ->label('scope', 'functions.write') - ->label('audits.event', 'functions.variables.delete') + ->label('audits.event', 'variable.delete') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'functions') diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 9040f10002..2d83768d3d 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -48,7 +48,7 @@ App::post('/v1/storage/buckets') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') - ->label('audits.event', 'buckets.create') + ->label('audits.event', 'bucket.create') ->label('audits.resource', 'buckets/{response.$id}') ->label('usage.metric', 'buckets.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -219,7 +219,7 @@ App::put('/v1/storage/buckets/:bucketId') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') - ->label('audits.event', 'buckets.update') + ->label('audits.event', 'bucket.update') ->label('audits.resource', 'buckets/{response.$id}') ->label('usage.metric', 'buckets.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -285,7 +285,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->desc('Delete Bucket') ->groups(['api', 'storage']) ->label('scope', 'buckets.write') - ->label('audits.event', 'buckets.delete') + ->label('audits.event', 'bucket.delete') ->label('event', 'buckets.[bucketId].delete') ->label('audits.resource', 'buckets/{request.bucketId}') ->label('usage.metric', 'buckets.{scope}.requests.delete') @@ -328,7 +328,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->desc('Create File') ->groups(['api', 'storage']) ->label('scope', 'files.write') - ->label('audits.event', 'files.create') + ->label('audits.event', 'file.create') ->label('event', 'buckets.[bucketId].files.[fileId].create') ->label('audits.resource', 'files/{response.$id}') ->label('usage.metric', 'files.{scope}.requests.create') @@ -1240,7 +1240,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') - ->label('audits.event', 'files.update') + ->label('audits.event', 'file.update') ->label('audits.resource', 'files/{response.$id}') ->label('usage.metric', 'files.{scope}.requests.update') ->label('usage.params', ['bucketId:{request.bucketId}']) @@ -1343,7 +1343,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ->groups(['api', 'storage']) ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].delete') - ->label('audits.event', 'files.delete') + ->label('audits.event', 'file.delete') ->label('audits.resource', 'file/{request.fileId}') ->label('usage.metric', 'files.{scope}.requests.delete') ->label('usage.params', ['bucketId:{request.bucketId}']) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index ecb6894627..19af59d08c 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -45,7 +45,7 @@ App::post('/v1/teams') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].create') ->label('scope', 'teams.write') - ->label('audits.event', 'teams.create') + ->label('audits.event', 'team.create') ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -200,7 +200,7 @@ App::put('/v1/teams/:teamId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].update') ->label('scope', 'teams.write') - ->label('audits.event', 'teams.update') + ->label('audits.event', 'team.update') ->label('audits.resource', 'team/{response.$id}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -236,7 +236,7 @@ App::delete('/v1/teams/:teamId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].delete') ->label('scope', 'teams.write') - ->label('audits.event', 'teams.delete') + ->label('audits.event', 'team.delete') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -291,7 +291,7 @@ App::post('/v1/teams/:teamId/memberships') ->label('event', 'teams.[teamId].memberships.[membershipId].create') ->label('scope', 'teams.write') ->label('auth.type', 'invites') - ->label('audits.event', 'teams.memberships.create') + ->label('audits.event', 'membership.create') ->label('audits.resource', 'team/{request.teamId}') ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) @@ -586,7 +586,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update') ->label('scope', 'teams.write') - ->label('audits.event', 'teams.memberships.update') + ->label('audits.event', 'membership.update') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') @@ -657,7 +657,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].update.status') ->label('scope', 'public') - ->label('audits.event', 'teams.memberships.status.update') + ->label('audits.event', 'membership.update') ->label('audits.resource', 'team/{request.teamId}') ->label('audits.userId', '{request.userId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -791,7 +791,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') ->groups(['api', 'teams']) ->label('event', 'teams.[teamId].memberships.[membershipId].delete') ->label('scope', 'teams.write') - ->label('audits.event', 'teams.memberships.delete') + ->label('audits.event', 'membership.delete') ->label('audits.resource', 'team/{request.teamId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'teams') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 5d9fff4cb7..ad14291e8d 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -88,7 +88,7 @@ App::post('/v1/users') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -118,7 +118,7 @@ App::post('/v1/users/bcrypt') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.bcrypt') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -147,7 +147,7 @@ App::post('/v1/users/md5') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.md5') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -176,7 +176,7 @@ App::post('/v1/users/argon2') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.argon2') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -205,7 +205,7 @@ App::post('/v1/users/sha') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.sha') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -241,7 +241,7 @@ App::post('/v1/users/phpass') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.phpass') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -270,7 +270,7 @@ App::post('/v1/users/scrypt') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.scrypt') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -312,7 +312,7 @@ App::post('/v1/users/scrypt-modified') ->groups(['api', 'users']) ->label('event', 'users.[userId].create') ->label('scope', 'users.write') - ->label('audits.event', 'users.create.scrypt-modified') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -609,7 +609,7 @@ App::patch('/v1/users/:userId/status') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.status') ->label('scope', 'users.write') - ->label('audits.event', 'users.status.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -646,7 +646,7 @@ App::patch('/v1/users/:userId/verification') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') - ->label('audits.event', 'users.verification.update') + ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -682,7 +682,7 @@ App::patch('/v1/users/:userId/verification/phone') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') - ->label('audits.event', 'users.verification.phone.update') + ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -718,7 +718,7 @@ App::patch('/v1/users/:userId/name') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.name') ->label('scope', 'users.write') - ->label('audits.event', 'users.name.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -759,7 +759,7 @@ App::patch('/v1/users/:userId/password') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.password') ->label('scope', 'users.write') - ->label('audits.event', 'users.password.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -801,7 +801,7 @@ App::patch('/v1/users/:userId/email') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.email') ->label('scope', 'users.write') - ->label('audits.event', 'users.email.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -848,7 +848,7 @@ App::patch('/v1/users/:userId/phone') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'users.write') - ->label('audits.event', 'users.phone.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -893,7 +893,7 @@ App::patch('/v1/users/:userId/verification') ->groups(['api', 'users']) ->label('event', 'users.[userId].update.verification') ->label('scope', 'users.write') - ->label('audits.event', 'users.verification.email.update') + ->label('audits.event', 'verification.update') ->label('audits.resource', 'user/{request.userId}') ->label('audits.userId', '{request.userId}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -963,7 +963,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->groups(['api', 'users']) ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('scope', 'users.write') - ->label('audits.event', 'users.session.delete') + ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{request.userId}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1006,7 +1006,7 @@ App::delete('/v1/users/:userId/sessions') ->groups(['api', 'users']) ->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('scope', 'users.write') - ->label('audits.event', 'users.sessions.delete') + ->label('audits.event', 'session.delete') ->label('audits.resource', 'user/{user.$id}') ->label('usage.metric', 'sessions.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) @@ -1049,7 +1049,7 @@ App::delete('/v1/users/:userId') ->groups(['api', 'users']) ->label('event', 'users.[userId].delete') ->label('scope', 'users.write') - ->label('audits.event', 'users.delete') + ->label('audits.event', 'user.delete') ->label('audits.resource', 'user/{request.userId}') ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 37c4277e85..9e59c50551 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -341,7 +341,7 @@ trait AccountBase $this->assertNotEmpty($response['body']['logs']); $this->assertCount(3, $response['body']['logs']); $this->assertIsNumeric($response['body']['total']); - $this->assertContains($response['body']['logs'][1]['event'], ["account.session.email.create"]); + $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, DateTime::isValid($response['body']['logs'][1]['time'])); From 5294f86595dbc368b5fea75f62e6f4068e3b17d1 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 5 Sep 2022 13:43:36 +0100 Subject: [PATCH 12/52] 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 13/52] 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 eb0b33bfcd0041b3869dbd12da1f33cac2f8ab95 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 02:12:04 +0000 Subject: [PATCH 14/52] Fix code examples in SDK getting started --- docs/sdks/android/GETTING_STARTED.md | 11 ++++++----- docs/sdks/dart/GETTING_STARTED.md | 8 ++++---- docs/sdks/deno/GETTING_STARTED.md | 10 +++++----- docs/sdks/dotnet/GETTING_STARTED.md | 10 ++++------ docs/sdks/flutter/GETTING_STARTED.md | 16 ++++++++-------- docs/sdks/kotlin/GETTING_STARTED.md | 18 ++++++++---------- docs/sdks/nodejs/GETTING_STARTED.md | 6 +++--- docs/sdks/php/GETTING_STARTED.md | 7 ++++--- docs/sdks/python/GETTING_STARTED.md | 5 +++-- docs/sdks/ruby/GETTING_STARTED.md | 6 +++--- docs/sdks/web/GETTING_STARTED.md | 4 ++-- 11 files changed, 50 insertions(+), 51 deletions(-) diff --git a/docs/sdks/android/GETTING_STARTED.md b/docs/sdks/android/GETTING_STARTED.md index 0c00bf6019..4549d7204b 100644 --- a/docs/sdks/android/GETTING_STARTED.md +++ b/docs/sdks/android/GETTING_STARTED.md @@ -51,7 +51,7 @@ When trying to connect to Appwrite from an emulator or a mobile device, localhos // Register User val account = Account(client) val response = account.create( - "[USER_ID]", + ID.unique(), "email@example.com", "password" ) @@ -62,6 +62,7 @@ val response = account.create( ```kotlin import io.appwrite.Client import io.appwrite.services.Account +import io.appwrite.ID val client = Client(context) .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint @@ -69,8 +70,8 @@ val client = Client(context) .setSelfSigned(true) // Remove in production val account = Account(client) -val response = account.create( - "[USER_ID]", +val user = account.create( + ID.unique(), "email@example.com", "password" ) @@ -81,8 +82,8 @@ The Appwrite Android SDK raises an `AppwriteException` object with `message`, `c ```kotlin try { - var response = account.create("[USER_ID]", "email@example.com", "password") - Log.d("Appwrite response", response.body?.string()) + var user = account.create(ID.unique(), "email@example.com", "password") + Log.d("Appwrite user", account.toMap()) } catch(e : AppwriteException) { Log.e("AppwriteException",e.message.toString()) } diff --git a/docs/sdks/dart/GETTING_STARTED.md b/docs/sdks/dart/GETTING_STARTED.md index e6c4ecf677..559c0894a3 100644 --- a/docs/sdks/dart/GETTING_STARTED.md +++ b/docs/sdks/dart/GETTING_STARTED.md @@ -16,8 +16,8 @@ void main() async { Users users = Users(client); try { - final response = await users.create(userId: '[USER_ID]', email: ‘email@example.com’,password: ‘password’, name: ‘name’); - print(response.data); + final user = await users.create(userId: ID.unique(), email: ‘email@example.com’,password: ‘password’, name: ‘name’); + print(user.toMap()); } on AppwriteException catch(e) { print(e.message); } @@ -31,8 +31,8 @@ The Appwrite Dart SDK raises `AppwriteException` object with `message`, `code` a Users users = Users(client); try { - final response = await users.create(userId: '[USER_ID]', email: ‘email@example.com’,password: ‘password’, name: ‘name’); - print(response.data); + final user = await users.create(userId: ID.unique(), email: ‘email@example.com’,password: ‘password’, name: ‘name’); + print(user.toMap()); } on AppwriteException catch(e) { //show message to user or do other operation based on error as required print(e.message); diff --git a/docs/sdks/deno/GETTING_STARTED.md b/docs/sdks/deno/GETTING_STARTED.md index 08c9eb461e..6546719a61 100644 --- a/docs/sdks/deno/GETTING_STARTED.md +++ b/docs/sdks/deno/GETTING_STARTED.md @@ -21,8 +21,8 @@ Once your SDK object is set, create any of the Appwrite service objects and choo ```typescript let users = new sdk.Users(client); -let response = await users.create('[USER_ID]', 'email@example.com', 'password'); -console.log(response); +let user = await users.create(ID.unique(), 'email@example.com', 'password'); +console.log(user); ``` ### Full Example @@ -39,8 +39,8 @@ client .setSelfSigned() // Use only on dev mode with a self-signed SSL cert ; -let response = await users.create('[USER_ID]', 'email@example.com', 'password'); -console.log(response); +let user = await users.create(ID.unique(), 'email@example.com', 'password'); +console.log(user); ``` ### Error Handling @@ -50,7 +50,7 @@ The Appwrite Deno SDK raises `AppwriteException` object with `message`, `code` a let users = new sdk.Users(client); try { - let response = await users.create('[USER_ID]', 'email@example.com', 'password'); + let user = await users.create(ID.unique(), 'email@example.com', 'password'); } catch(e) { console.log(e.message); } diff --git a/docs/sdks/dotnet/GETTING_STARTED.md b/docs/sdks/dotnet/GETTING_STARTED.md index cffbce2078..fe8e81499a 100644 --- a/docs/sdks/dotnet/GETTING_STARTED.md +++ b/docs/sdks/dotnet/GETTING_STARTED.md @@ -20,9 +20,8 @@ static async Task Main(string[] args) var users = Users(client); try { - var request = await users.create('[USER_ID]', 'email@example.com', 'password', 'name'); - var response = await request.Content.ReadAsStringAsync(); - Console.WriteLine(response); + var user = await users.create(ID.unique(), 'email@example.com', 'password', 'name'); + Console.WriteLine(user.ToMap()); } catch (AppwriteException e) { Console.WriteLine(e.Message); } @@ -36,9 +35,8 @@ The Appwrite .NET SDK raises `AppwriteException` object with `message`, `code` a var users = Users(client); try { - var request = await users.create('[USER_ID]', 'email@example.com', 'password', 'name'); - var response = await request.Content.ReadAsStringAsync(); - Console.WriteLine(response); + var user = await users.create(ID.unique(), 'email@example.com', 'password', 'name'); + Console.WriteLine(user.ToMap()); } catch (AppwriteException e) { Console.WriteLine(e.Message); } diff --git a/docs/sdks/flutter/GETTING_STARTED.md b/docs/sdks/flutter/GETTING_STARTED.md index a9c121d2b9..78a334e9f7 100644 --- a/docs/sdks/flutter/GETTING_STARTED.md +++ b/docs/sdks/flutter/GETTING_STARTED.md @@ -101,9 +101,9 @@ When trying to connect to Appwrite from an emulator or a mobile device, localhos ```dart // Register User Account account = Account(client); -Response user = await account +final user = await account .create( - userId: '[USER_ID]', + userId: ID.unique(), email: 'me@appwrite.io', password: 'password', name: 'My Name' @@ -129,9 +129,9 @@ void main() { // Register User Account account = Account(client); - Response user = await account + final user = await account .create( - userId: '[USER_ID]', + userId: ID.unique(), email: 'me@appwrite.io', password: 'password', name: 'My Name' @@ -140,14 +140,14 @@ void main() { ``` ### Error Handling -The Appwrite Flutter SDK raises `AppwriteException` object with `message`, `code` and `response` properties. You can handle any errors by catching `AppwriteException` and present the `message` to the user or handle it yourself based on the provided error information. Below is an example. +The Appwrite Flutter SDK raises `AppwriteException` object with `message`, `type`, `code` and `response` properties. You can handle any errors by catching `AppwriteException` and present the `message` to the user or handle it yourself based on the provided error information. Below is an example. ```dart -Users users = Users(client); +Account account = Account(client); try { - final response = await users.create(userId: '[USER_ID]', email: ‘email@example.com’,password: ‘password’, name: ‘name’); - print(response.data); + final user = await account.create(userId: ID.unique(), email: ‘email@example.com’,password: ‘password’, name: ‘name’); + print(user.toMap()); } on AppwriteException catch(e) { //show message to user or do other operation based on error as required print(e.message); diff --git a/docs/sdks/kotlin/GETTING_STARTED.md b/docs/sdks/kotlin/GETTING_STARTED.md index be4da1a090..a419d36cb1 100644 --- a/docs/sdks/kotlin/GETTING_STARTED.md +++ b/docs/sdks/kotlin/GETTING_STARTED.md @@ -23,12 +23,11 @@ Once your SDK object is set, create any of the Appwrite service objects and choo ```kotlin val users = Users(client) -val response = users.create( - user = "[USER_ID]", +val user = users.create( + user = ID.unique(), email = "email@example.com", password = "password", ) -val json = response.body?.string() ``` ### Full Example @@ -36,6 +35,7 @@ val json = response.body?.string() ```kotlin import io.appwrite.Client import io.appwrite.services.Users +import io.appwrite.ID suspend fun main() { val client = Client(context) @@ -45,12 +45,11 @@ suspend fun main() { .setSelfSigned(true) // Use only on dev mode with a self-signed SSL cert val users = Users(client) - val response = users.create( - user = "[USER_ID]", + val user = users.create( + user = ID.unique(), email = "email@example.com", password = "password", ) - val json = response.body?.string() } ``` @@ -60,18 +59,17 @@ The Appwrite Kotlin SDK raises `AppwriteException` object with `message`, `code` ```kotlin import io.appwrite.Client +import io.appwrite.ID import io.appwrite.services.Users suspend fun main() { val users = Users(client) try { - val response = users.create( - user = "[USER_ID]", + val user = users.create( + user = ID.unique(), email = "email@example.com", password = "password", ) - var jsonString = response.body?.string() ?: "" - } catch (e: AppwriteException) { println(e) } diff --git a/docs/sdks/nodejs/GETTING_STARTED.md b/docs/sdks/nodejs/GETTING_STARTED.md index 7db3288479..70767e159b 100644 --- a/docs/sdks/nodejs/GETTING_STARTED.md +++ b/docs/sdks/nodejs/GETTING_STARTED.md @@ -22,7 +22,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo ```js let users = new sdk.Users(client); -let promise = users.create('[USER_ID]', 'email@example.com', 'password'); +let promise = users.create(ID.unique(), 'email@example.com', 'password'); promise.then(function (response) { console.log(response); @@ -45,7 +45,7 @@ client ; let users = new sdk.Users(client); -let promise = users.create('[USER_ID]', 'email@example.com', 'password'); +let promise = users.create(ID.unique(), 'email@example.com', 'password'); promise.then(function (response) { console.log(response); @@ -61,7 +61,7 @@ The Appwrite Node SDK raises `AppwriteException` object with `message`, `code` a let users = new sdk.Users(client); try { - let res = await users.create('[USER_ID]', 'email@example.com', 'password'); + let res = await users.create(ID.unique(), 'email@example.com', 'password'); } catch(e) { console.log(e.message); } diff --git a/docs/sdks/php/GETTING_STARTED.md b/docs/sdks/php/GETTING_STARTED.md index 0dcb7f2475..faa3dcf654 100644 --- a/docs/sdks/php/GETTING_STARTED.md +++ b/docs/sdks/php/GETTING_STARTED.md @@ -20,12 +20,13 @@ Once your SDK object is set, create any of the Appwrite service objects and choo ```php $users = new Users($client); -$result = $users->create('email@example.com', 'password'); +$user = $users->create(ID::unique(), 'email@example.com', 'password'); ``` ### Full Example ```php use Appwrite\Client; +use Appwrite\ID; use Appwrite\Services\Users; $client = new Client(); @@ -39,7 +40,7 @@ $client $users = new Users($client); -$result = $users->create('[USER_ID]', 'email@example.com', 'password'); +$user = $users->create(ID::unique(), 'email@example.com', 'password'); ``` ### Error Handling @@ -48,7 +49,7 @@ The Appwrite PHP SDK raises `AppwriteException` object with `message`, `code` an ```php $users = new Users($client); try { - $result = $users->create('[USER_ID]', 'email@example.com', 'password'); + $user = $users->create(ID::unique(), 'email@example.com', 'password'); } catch(AppwriteException $error) { echo $error->message; } diff --git a/docs/sdks/python/GETTING_STARTED.md b/docs/sdks/python/GETTING_STARTED.md index 46a3001ab9..a7772c9f5d 100644 --- a/docs/sdks/python/GETTING_STARTED.md +++ b/docs/sdks/python/GETTING_STARTED.md @@ -30,6 +30,7 @@ result = users.create('[USER_ID]', 'email@example.com', 'password') ```python from appwrite.client import Client from appwrite.services.users import Users +from appwrite.client import ID client = Client() @@ -42,7 +43,7 @@ client = Client() users = Users(client) -result = users.create('[USER_ID]', 'email@example.com', 'password') +result = users.create(ID.unique(), 'email@example.com', 'password') ``` ### Error Handling @@ -51,7 +52,7 @@ The Appwrite Python SDK raises `AppwriteException` object with `message`, `code` ```python users = Users(client) try: - result = users.create('[USER_ID]', 'email@example.com', 'password') + result = users.create(ID.unique(), 'email@example.com', 'password') except AppwriteException as e: print(e.message) ``` diff --git a/docs/sdks/ruby/GETTING_STARTED.md b/docs/sdks/ruby/GETTING_STARTED.md index ff714c103c..da10e1aebc 100644 --- a/docs/sdks/ruby/GETTING_STARTED.md +++ b/docs/sdks/ruby/GETTING_STARTED.md @@ -22,7 +22,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo ```ruby users = Appwrite::Users.new(client); -result = users.create(userId: '[USER_ID]', email: 'email@example.com', password: 'password'); +user = users.create(userId: Appwrite::ID::unique(), email: 'email@example.com', password: 'password'); ``` ### Full Example @@ -40,7 +40,7 @@ client users = Appwrite::Users.new(client); -result = users.create(userId: '[USER_ID]', email: 'email@example.com', password: 'password'); +user = users.create(userId: Appwrite::ID::unique(), email: 'email@example.com', password: 'password'); ``` ### Error Handling @@ -50,7 +50,7 @@ The Appwrite Ruby SDK raises `Appwrite::Exception` object with `message`, `code` users = Appwrite::Users.new(client); begin - result = users.create(userId: '[USER_ID]', email: 'email@example.com', password: 'password'); + user = users.create(userId: Appwrite::ID::unique(), email: 'email@example.com', password: 'password'); rescue Appwrite::Exception => error puts error.message end diff --git a/docs/sdks/web/GETTING_STARTED.md b/docs/sdks/web/GETTING_STARTED.md index a1d387d7d4..2c09704af2 100644 --- a/docs/sdks/web/GETTING_STARTED.md +++ b/docs/sdks/web/GETTING_STARTED.md @@ -25,7 +25,7 @@ Once your SDK object is set, access any of the Appwrite services and choose any const account = new Account(client); // Register User -account.create('[USER_ID]', 'me@example.com', 'password', 'Jane Doe') +account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') .then(function (response) { console.log(response); }, function (error) { @@ -47,7 +47,7 @@ client const account = new Account(client); // Register User -account.create('[USER_ID]', 'me@example.com', 'password', 'Jane Doe') +account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') .then(function (response) { console.log(response); }, function (error) { From cb8688a8c3da3a0ccc791224a73c87976a19cbb0 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 7 Sep 2022 14:43:50 +1200 Subject: [PATCH 15/52] Update and move swift getting started docs to right location --- .../sdks/{swift-client => apple}/CHANGELOG.md | 0 .../GETTING_STARTED.md | 66 ++++++++------ docs/sdks/swift-server/GETTING_STARTED.md | 83 ----------------- .../sdks/{swift-server => swift}/CHANGELOG.md | 0 docs/sdks/swift/GETTING_STARTED.md | 91 +++++++++++++++++++ 5 files changed, 128 insertions(+), 112 deletions(-) rename docs/sdks/{swift-client => apple}/CHANGELOG.md (100%) rename docs/sdks/{swift-client => apple}/GETTING_STARTED.md (62%) delete mode 100644 docs/sdks/swift-server/GETTING_STARTED.md rename docs/sdks/{swift-server => swift}/CHANGELOG.md (100%) create mode 100644 docs/sdks/swift/GETTING_STARTED.md diff --git a/docs/sdks/swift-client/CHANGELOG.md b/docs/sdks/apple/CHANGELOG.md similarity index 100% rename from docs/sdks/swift-client/CHANGELOG.md rename to docs/sdks/apple/CHANGELOG.md diff --git a/docs/sdks/swift-client/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md similarity index 62% rename from docs/sdks/swift-client/GETTING_STARTED.md rename to docs/sdks/apple/GETTING_STARTED.md index 51e5a5bc83..213ab764ac 100644 --- a/docs/sdks/swift-client/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -53,30 +53,35 @@ For UIKit, you need to add the following function to your `SceneDelegate.swift`. ### Init your SDK -Initialize your SDK with your Appwrite server API endpoint and project ID which can be found in your project settings page and your new API secret Key project API keys section. +Initialize your SDK with your Appwrite server API endpoint and project ID which can be found in your project settings page. ```swift import Appwrite func main() { let client = Client() - .setEndpoint("http://[HOSTNAME_OR_IP]/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID - .setSelfSigned() // Use only on dev mode with a self-signed SSL cert + .setEndpoint("http://[HOSTNAME_OR_IP]/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setSelfSigned() // Use only on dev mode with a self-signed SSL cert } ``` ### Make Your First Request -Once your SDK object is set, create any of the Appwrite service objects and choose any request to send. Full documentation for any service method you would like to use can be found in your SDK documentation or in the [API References](https://appwrite.io/docs) section. +Once your SDK object is initialized, create any of the Appwrite service objects and choose any request to send. Full documentation for any service method you would like to use can be found in your SDK documentation or in the [API References](https://appwrite.io/docs) section. ```swift -let users = Users(client: client) -users.create(userId: "[USER_ID]", email: "email@example.com", password: "password") { result in - switch result { - case .failure(let error): print(error.message) - case .success(let user): print(String(describing: user)) - } +let account = Account(client) + +do { + let account = try await account.create( + userId: ID.unique(), + email: "email@example.com", + password: "password" + ) + print(String(describing: account.toMap())) +} catch { + print(error.localizedDescription) } ``` @@ -87,37 +92,40 @@ import Appwrite func main() { let client = Client() - .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID - .setSelfSigned() // Use only on dev mode with a self-signed SSL cert + .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setSelfSigned() // Use only on dev mode with a self-signed SSL cert - let users = Users(client: client) - users.create(userId: "[USER_ID]", email: "email@example.com", password: "password") { result in - switch result { - case .failure(let error): print(error.message) - case .success(let user): print(String(describing: user)) - } + let account = Account(client) + + do { + let account = try await account.create( + userId: ID.unique(), + email: "email@example.com", + password: "password" + ) + print(String(describing: account.toMap())) + } catch { + print(error.localizedDescription) } } ``` ### Error Handling -When an error occurs, the Appwrite Swift SDK responds with a result wrapping an `AppwriteError` object with `message` and `code` properties. You can handle any errors in the result's `.failure` case and present the `message` to the user or handle it yourself based on the provided error information. Below is an example. +When an error occurs, the Appwrite Apple SDK throws an `AppwriteError` object with `message` and `code` properties. You can handle any errors in a catch block and present the `message` or `localizedDescription` to the user or handle it yourself based on the provided error information. Below is an example. ```swift import Appwrite func main() { - let users = Users(client: client) + let account = Account(client) - users.create(userId: "[USER_ID]", email: "email@example.com", password: "password") { result in - switch result { - case .failure(let error): - print(error.message) - case .success(var response): - ... - } + do { + let account = try await account.get() + print(String(describing: account.toMap())) + } catch { + print(error.localizedDescription) } } ``` diff --git a/docs/sdks/swift-server/GETTING_STARTED.md b/docs/sdks/swift-server/GETTING_STARTED.md deleted file mode 100644 index c27fbb34a0..0000000000 --- a/docs/sdks/swift-server/GETTING_STARTED.md +++ /dev/null @@ -1,83 +0,0 @@ -## Getting Started - -### Init your SDK - -Initialize your SDK with your Appwrite server API endpoint and project ID which can be found in your project settings page and your new API secret Key project API keys section. - -```swift -import Appwrite - -func main() { - let client = Client() - .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID - .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key - .setSelfSigned() // Use only on dev mode with a self-signed SSL cert -} -``` - -### Make Your First Request - -Once your SDK object is set, create any of the Appwrite service objects and choose any request to send. Full documentation for any service method you would like to use can be found in your SDK documentation or in the [API References](https://appwrite.io/docs) section. - -```swift -let users = Users(client: client) -users.create(userId: "[USER_ID]", email: "email@example.com", password: "password") { result in - switch result { - case .failure(let error): print(error.message) - case .success(let user): print(String(describing: user)) - } -} -``` - -### Full Example - -```swift -import Appwrite - -func main() { - let client = Client() - .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint - .setProject("5df5acd0d48c2") // Your project ID - .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key - .setSelfSigned() // Use only on dev mode with a self-signed SSL cert - - let users = Users(client: client) - users.create(userId: "[USER_ID]", email: "email@example.com", password: "password") { result in - switch result { - case .failure(let error): print(error.message) - case .success(let user): print(String(describing: user)) - } - } -} -``` - -### Error Handling - -When an error occurs, the Appwrite Swift SDK responds with a result wrapping an `AppwriteError` object with `message` and `code` properties. You can handle any errors in the result's `.failure` case and present the `message` to the user or handle it yourself based on the provided error information. Below is an example. - -```swift -import Appwrite - -func main() { - let users = Users(client: client) - - users.create(userId: "[USER_ID]", email: "email@example.com", password: "password") { result in - switch result { - case .failure(let error): - print(error.message) - case .success(var response): - ... - } - } -} -``` - -### Learn more - -You can use the following resources to learn more and get help - -- 🚀 [Getting Started Tutorial](https://appwrite.io/docs/getting-started-for-server) -- 📜 [Appwrite Docs](https://appwrite.io/docs) -- 💬 [Discord Community](https://appwrite.io/discord) -- 🚂 [Appwrite Swift Playground](https://github.com/appwrite/playground-for-swift-server) diff --git a/docs/sdks/swift-server/CHANGELOG.md b/docs/sdks/swift/CHANGELOG.md similarity index 100% rename from docs/sdks/swift-server/CHANGELOG.md rename to docs/sdks/swift/CHANGELOG.md diff --git a/docs/sdks/swift/GETTING_STARTED.md b/docs/sdks/swift/GETTING_STARTED.md new file mode 100644 index 0000000000..e0fb45dd7d --- /dev/null +++ b/docs/sdks/swift/GETTING_STARTED.md @@ -0,0 +1,91 @@ +## Getting Started + +### Init your SDK + +Initialize your SDK with your Appwrite server API endpoint and project ID which can be found in your project settings page and your new API secret Key project API keys section. + +```swift +import Appwrite + +func main() { + let client = Client() + .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d184...a2ae413dad2") // Your secret API key + .setSelfSigned() // Use only on dev mode with a self-signed SSL cert +} +``` + +### Make Your First Request + +Once your SDK object is initialized, create any of the Appwrite service objects and choose any request to send. Full documentation for any service method you would like to use can be found in your SDK documentation or in the [API References](https://appwrite.io/docs) section. + +```swift +let users = Users(client) + +do { + let user = try await users.create( + userId: ID.unique(), + email: "email@example.com", + password: "password" + ) + print(String(describing: user.toMap())) +} catch { + print(error.localizedDescription) +} +``` + +### Full Example + +```swift +import Appwrite + +func main() { + let client = Client() + .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint + .setProject("5df5acd0d48c2") // Your project ID + .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key + .setSelfSigned() // Use only on dev mode with a self-signed SSL cert + + let users = Users(client) + + do { + let user = try await users.create( + userId: ID.unique(), + email: "email@example.com", + password: "password" + ) + print(String(describing: user.toMap())) + } catch { + print(error.localizedDescription) + } +} +``` + +### Error Handling + +When an error occurs, the Appwrite Swift SDK throws an `AppwriteError` object with `message` and `code` properties. You can handle any errors in a catch block and present the `message` or `localizedDescription` to the user or handle it yourself based on the provided error information. Below is an example. + +```swift +import Appwrite + +func main() { + let users = Users(client) + + do { + let users = try await users.list() + print(String(describing: users.toMap())) + } catch { + print(error.localizedDescription) + } +} +``` + +### Learn more + +You can use the following resources to learn more and get help + +- 🚀 [Getting Started Tutorial](https://appwrite.io/docs/getting-started-for-server) +- 📜 [Appwrite Docs](https://appwrite.io/docs) +- 💬 [Discord Community](https://appwrite.io/discord) +- 🚂 [Appwrite Swift Playground](https://github.com/appwrite/playground-for-swift-server) From fb3ba9a47512a98901041603bc55096c73beea8a Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:05:38 +0545 Subject: [PATCH 16/52] Update docs/sdks/android/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/android/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/android/GETTING_STARTED.md b/docs/sdks/android/GETTING_STARTED.md index 4549d7204b..bb312390fc 100644 --- a/docs/sdks/android/GETTING_STARTED.md +++ b/docs/sdks/android/GETTING_STARTED.md @@ -85,7 +85,7 @@ try { var user = account.create(ID.unique(), "email@example.com", "password") Log.d("Appwrite user", account.toMap()) } catch(e : AppwriteException) { - Log.e("AppwriteException",e.message.toString()) + e.printStackTrace() } ``` From e24d789510fc54ced6d1e3b3e51f1783f4bcd622 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:05:44 +0545 Subject: [PATCH 17/52] Update docs/sdks/apple/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/apple/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/apple/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md index 213ab764ac..755fa4f93b 100644 --- a/docs/sdks/apple/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -74,7 +74,7 @@ Once your SDK object is initialized, create any of the Appwrite service objects let account = Account(client) do { - let account = try await account.create( + let user = try await account.create( userId: ID.unique(), email: "email@example.com", password: "password" From 50d20f7e840b82698c6e1e71a5fc3a2107541f57 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:05:50 +0545 Subject: [PATCH 18/52] Update docs/sdks/android/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/android/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/android/GETTING_STARTED.md b/docs/sdks/android/GETTING_STARTED.md index bb312390fc..684f98e0f6 100644 --- a/docs/sdks/android/GETTING_STARTED.md +++ b/docs/sdks/android/GETTING_STARTED.md @@ -83,7 +83,7 @@ The Appwrite Android SDK raises an `AppwriteException` object with `message`, `c ```kotlin try { var user = account.create(ID.unique(), "email@example.com", "password") - Log.d("Appwrite user", account.toMap()) + Log.d("Appwrite user", user.toMap()) } catch(e : AppwriteException) { e.printStackTrace() } From a342a77caf720261571efbb7a31823dd2a4a04ef Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:05:56 +0545 Subject: [PATCH 19/52] Update docs/sdks/apple/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/apple/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/apple/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md index 755fa4f93b..129947ad24 100644 --- a/docs/sdks/apple/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -79,7 +79,7 @@ do { email: "email@example.com", password: "password" ) - print(String(describing: account.toMap())) + print(String(describing: user.toMap())) } catch { print(error.localizedDescription) } From 4acd4a03d32f55d9033c321a24fd1720cac5652c Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:06:02 +0545 Subject: [PATCH 20/52] Update docs/sdks/apple/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/apple/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/apple/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md index 129947ad24..bbc9b085f3 100644 --- a/docs/sdks/apple/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -123,7 +123,7 @@ func main() { do { let account = try await account.get() - print(String(describing: account.toMap())) + print(String(describing: user.toMap())) } catch { print(error.localizedDescription) } From 0fd027b957f2cddaa991a4ab28136baba569affd Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:06:33 +0545 Subject: [PATCH 21/52] Update docs/sdks/dotnet/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/dotnet/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/dotnet/GETTING_STARTED.md b/docs/sdks/dotnet/GETTING_STARTED.md index fe8e81499a..46396c106c 100644 --- a/docs/sdks/dotnet/GETTING_STARTED.md +++ b/docs/sdks/dotnet/GETTING_STARTED.md @@ -20,7 +20,7 @@ static async Task Main(string[] args) var users = Users(client); try { - var user = await users.create(ID.unique(), 'email@example.com', 'password', 'name'); + var user = await users.Create(ID.Unique(), 'email@example.com', 'password', 'name'); Console.WriteLine(user.ToMap()); } catch (AppwriteException e) { Console.WriteLine(e.Message); From 90e05fec8785320e4cd5a91a2b376e26cf281d12 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:06:38 +0545 Subject: [PATCH 22/52] Update docs/sdks/dotnet/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/dotnet/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/dotnet/GETTING_STARTED.md b/docs/sdks/dotnet/GETTING_STARTED.md index 46396c106c..23bab6f70a 100644 --- a/docs/sdks/dotnet/GETTING_STARTED.md +++ b/docs/sdks/dotnet/GETTING_STARTED.md @@ -35,7 +35,7 @@ The Appwrite .NET SDK raises `AppwriteException` object with `message`, `code` a var users = Users(client); try { - var user = await users.create(ID.unique(), 'email@example.com', 'password', 'name'); + var user = await users.Create(ID.Unique(), 'email@example.com', 'password', 'name'); Console.WriteLine(user.ToMap()); } catch (AppwriteException e) { Console.WriteLine(e.Message); From b7e9d4894edf8e177d1f7fa9abe3ee6b54b945a5 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:06:43 +0545 Subject: [PATCH 23/52] Update docs/sdks/kotlin/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/kotlin/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/kotlin/GETTING_STARTED.md b/docs/sdks/kotlin/GETTING_STARTED.md index a419d36cb1..99d5e719af 100644 --- a/docs/sdks/kotlin/GETTING_STARTED.md +++ b/docs/sdks/kotlin/GETTING_STARTED.md @@ -71,7 +71,7 @@ suspend fun main() { password = "password", ) } catch (e: AppwriteException) { - println(e) + e.printStackTrace() } } ``` From f18707c3a03b388069cfac1cba366f98d9d8e284 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:06:51 +0545 Subject: [PATCH 24/52] Update docs/sdks/python/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/python/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/python/GETTING_STARTED.md b/docs/sdks/python/GETTING_STARTED.md index a7772c9f5d..9f693b65c6 100644 --- a/docs/sdks/python/GETTING_STARTED.md +++ b/docs/sdks/python/GETTING_STARTED.md @@ -30,7 +30,7 @@ result = users.create('[USER_ID]', 'email@example.com', 'password') ```python from appwrite.client import Client from appwrite.services.users import Users -from appwrite.client import ID +from appwrite.id import ID client = Client() From af1d1dd7a27eeca05f3227594501b8968eeda40b Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 7 Sep 2022 11:06:59 +0545 Subject: [PATCH 25/52] Update docs/sdks/apple/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/apple/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/apple/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md index bbc9b085f3..de2f233189 100644 --- a/docs/sdks/apple/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -99,7 +99,7 @@ func main() { let account = Account(client) do { - let account = try await account.create( + let user = try await account.create( userId: ID.unique(), email: "email@example.com", password: "password" From 80e60d9d95bc896555fe59c8aaa233d5880b72fe Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 7 Sep 2022 11:26:22 +0100 Subject: [PATCH 26/52] 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 27/52] 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 5652e2d94feb08da13fa2c216d3908012ba83090 Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 8 Sep 2022 15:16:54 +0300 Subject: [PATCH 28/52] audits.resource label update --- app/controllers/api/storage.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 5fc8be7ba1..1134887fb6 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -49,7 +49,7 @@ App::post('/v1/storage/buckets') ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].create') ->label('audits.event', 'bucket.create') - ->label('audits.resource', 'buckets/{response.$id}') + ->label('audits.resource', 'bucket/{response.$id}') ->label('usage.metric', 'buckets.{scope}.requests.create') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -221,7 +221,7 @@ App::put('/v1/storage/buckets/:bucketId') ->label('scope', 'buckets.write') ->label('event', 'buckets.[bucketId].update') ->label('audits.event', 'bucket.update') - ->label('audits.resource', 'buckets/{response.$id}') + ->label('audits.resource', 'bucket/{response.$id}') ->label('usage.metric', 'buckets.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -288,7 +288,7 @@ App::delete('/v1/storage/buckets/:bucketId') ->label('scope', 'buckets.write') ->label('audits.event', 'bucket.delete') ->label('event', 'buckets.[bucketId].delete') - ->label('audits.resource', 'buckets/{request.bucketId}') + ->label('audits.resource', 'bucket/{request.bucketId}') ->label('usage.metric', 'buckets.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'storage') @@ -331,7 +331,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->label('scope', 'files.write') ->label('audits.event', 'file.create') ->label('event', 'buckets.[bucketId].files.[fileId].create') - ->label('audits.resource', 'files/{response.$id}') + ->label('audits.resource', 'file/{response.$id}') ->label('usage.metric', 'files.{scope}.requests.create') ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') @@ -1243,7 +1243,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') ->label('scope', 'files.write') ->label('event', 'buckets.[bucketId].files.[fileId].update') ->label('audits.event', 'file.update') - ->label('audits.resource', 'files/{response.$id}') + ->label('audits.resource', 'file/{response.$id}') ->label('usage.metric', 'files.{scope}.requests.update') ->label('usage.params', ['bucketId:{request.bucketId}']) ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}') From 342c4a3253816b9fb72b6ede26a617e31e0c362e Mon Sep 17 00:00:00 2001 From: shimon Date: Thu, 8 Sep 2022 16:06:16 +0300 Subject: [PATCH 29/52] audits.resource label update --- app/controllers/api/account.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 4254a39148..88fc37e934 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -53,7 +53,7 @@ App::post('/v1/account') ->label('event', 'users.[userId].create') ->label('scope', 'public') ->label('auth.type', 'emailPassword') - ->label('audits.event', 'account.create') + ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.create') @@ -1451,7 +1451,7 @@ App::patch('/v1/account/name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') - ->label('audits.event', 'account.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1482,7 +1482,7 @@ App::patch('/v1/account/password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') - ->label('audits.event', 'account.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') @@ -1522,7 +1522,7 @@ App::patch('/v1/account/email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') - ->label('audits.event', 'account.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1574,7 +1574,7 @@ App::patch('/v1/account/phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') - ->label('audits.event', 'account.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1622,7 +1622,7 @@ App::patch('/v1/account/prefs') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') - ->label('audits.event', 'account.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.update') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) @@ -1651,7 +1651,7 @@ App::patch('/v1/account/status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') - ->label('audits.event', 'account.update') + ->label('audits.event', 'user.update') ->label('audits.resource', 'user/{response.$id}') ->label('usage.metric', 'users.{scope}.requests.delete') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) From ddd15921a3795869d0e0528ae53f0d6dfd070580 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 8 Sep 2022 23:55:29 +0000 Subject: [PATCH 30/52] 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 fd6a3ed30cecd03b8648f9c40d56261581f6e61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 9 Sep 2022 08:05:33 +0000 Subject: [PATCH 31/52] Fix listVariables returing all variables --- app/controllers/api/functions.php | 3 +++ composer.lock | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 57928f5f1c..26c8ffc006 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -1376,6 +1376,9 @@ App::get('/v1/functions/:functionId/variables') $queries[] = Query::search('search', $search); } + // Apply internal queries + $queries[] = Query::equal('functionInternalId', [$function->getInternalId()]); + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE); $cursor = reset($cursor); diff --git a/composer.lock b/composer.lock index 8245baac5f..1f61b8aef6 100644 --- a/composer.lock +++ b/composer.lock @@ -2060,16 +2060,16 @@ }, { "name": "utopia-php/database", - "version": "0.25.1", + "version": "0.25.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "9d013ce3c111d1477d7986483f1003dcab2b9d14" + "reference": "140bbedf1c4d622990fb94d26681fcca235cd5b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/9d013ce3c111d1477d7986483f1003dcab2b9d14", - "reference": "9d013ce3c111d1477d7986483f1003dcab2b9d14", + "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.25.1" + "source": "https://github.com/utopia-php/database/tree/0.25.2" }, - "time": "2022-09-07T14:47:52+00:00" + "time": "2022-09-09T03:58:01+00:00" }, { "name": "utopia-php/domains", @@ -5384,5 +5384,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } From b41aaefc7e5ffe3707e27f788b52660646c85c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 9 Sep 2022 08:49:18 +0000 Subject: [PATCH 32/52] Implement 'enabled' attribute for functions --- app/config/collections.php | 19 ++++++----- app/controllers/api/functions.php | 35 ++++++++++++++------- src/Appwrite/Utopia/Response/Model/Func.php | 10 +++--- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 633e2c33b9..6396e255cb 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -2084,15 +2084,14 @@ $collections = [ 'filters' => [], ], [ - 'array' => false, - '$id' => ID::custom('status'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, + '$id' => ID::custom('enabled'), + 'type' => Database::VAR_BOOLEAN, 'signed' => true, - 'required' => false, - 'default' => null, + 'size' => 0, + 'format' => '', 'filters' => [], + 'required' => true, + 'array' => false, ], [ '$id' => ID::custom('runtime'), @@ -2210,10 +2209,10 @@ $collections = [ 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_status'), + '$id' => ID::custom('_key_enabled'), 'type' => Database::INDEX_KEY, - 'attributes' => ['status'], - 'lengths' => [Database::LENGTH_KEY], + 'attributes' => ['enabled'], + 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 26c8ffc006..375ac0e453 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -76,7 +76,7 @@ App::post('/v1/functions') $function = $dbForProject->createDocument('functions', new Document([ '$id' => $functionId, 'execute' => $execute, - 'status' => 'disabled', + 'enabled' => true, 'name' => $name, 'runtime' => $runtime, 'deployment' => '', @@ -424,12 +424,13 @@ App::put('/v1/functions/:functionId') ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true) + ->param('enabled', true, new Boolean(), 'Is collection enabled?', true) ->inject('response') ->inject('dbForProject') ->inject('project') ->inject('user') ->inject('events') - ->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) { + ->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) { $function = $dbForProject->getDocument('functions', $functionId); @@ -441,6 +442,8 @@ App::put('/v1/functions/:functionId') $cron = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null; $next = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null; + $enabled ??= $function->getAttribute('enabled', true); + $function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [ 'execute' => $execute, 'name' => $name, @@ -448,6 +451,7 @@ App::put('/v1/functions/:functionId') 'schedule' => $schedule, 'scheduleNext' => $next, 'timeout' => $timeout, + 'enabled' => $enabled, 'search' => implode(' ', [$functionId, $name, $function->getAttribute('runtime')]), ]))); @@ -945,12 +949,15 @@ App::post('/v1/functions/:functionId/executions') ->inject('user') ->inject('events') ->inject('usage') - ->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, Stats $usage) { + ->inject('mode') + ->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, Stats $usage, string $mode) { $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty()) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); + if ($function->isEmpty() || !$function->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } } $runtimes = Config::getParam('runtimes', []); @@ -1137,12 +1144,15 @@ App::get('/v1/functions/:functionId/executions') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') - ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject) { + ->inject('mode') + ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) { $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty()) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); + if ($function->isEmpty() || !$function->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } } $queries = Query::parseQueries($queries); @@ -1206,12 +1216,15 @@ App::get('/v1/functions/:functionId/executions/:executionId') ->param('executionId', '', new UID(), 'Execution ID.') ->inject('response') ->inject('dbForProject') - ->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject) { + ->inject('mode') + ->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, string $mode) { $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); - if ($function->isEmpty()) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); + if ($function->isEmpty() || !$function->getAttribute('enabled')) { + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } } $execution = $dbForProject->getDocument('executions', $executionId); diff --git a/src/Appwrite/Utopia/Response/Model/Func.php b/src/Appwrite/Utopia/Response/Model/Func.php index fbe23bab0b..c7e69fff88 100644 --- a/src/Appwrite/Utopia/Response/Model/Func.php +++ b/src/Appwrite/Utopia/Response/Model/Func.php @@ -43,11 +43,11 @@ class Func extends Model 'default' => '', 'example' => 'My Function', ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Function status. Possible values: `disabled`, `enabled`', - 'default' => '', - 'example' => 'enabled', + ->addRule('enabled', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Function enabled.', + 'default' => true, + 'example' => false, ]) ->addRule('runtime', [ 'type' => self::TYPE_STRING, From 668ebe4f4192c6392db35382adb055361105e522 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Fri, 9 Sep 2022 17:44:57 +0000 Subject: [PATCH 33/52] 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 34/52] 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 34dda741764229e7a8f65e52627a7e5c70e3c24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 11 Sep 2022 08:31:40 +0000 Subject: [PATCH 35/52] Update tests, fix bug --- src/Appwrite/Utopia/Database/Validator/Queries/Functions.php | 2 +- tests/e2e/Services/Functions/FunctionsCustomServerTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php index ee4c311163..a2ba368953 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Functions.php @@ -6,7 +6,7 @@ class Functions extends Base { public const ALLOWED_ATTRIBUTES = [ 'name', - 'status', + 'enabled', 'runtime', 'deployment', 'schedule', diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 8e3fd47b38..2d037abbf2 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -140,7 +140,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("status", "disabled")' ] + 'queries' => [ 'equal("enabled", true)' ] ]); $this->assertEquals($response['headers']['status-code'], 200); @@ -150,7 +150,7 @@ class FunctionsCustomServerTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => [ 'equal("status", "enabled")' ] + 'queries' => [ 'equal("enabled", false)' ] ]); $this->assertEquals($response['headers']['status-code'], 200); From 85b714857fa8c9890782d9be8e722ce607ed7afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 11 Sep 2022 18:43:42 +0000 Subject: [PATCH 36/52] Fix delete button redirect --- app/views/console/databases/collection.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/console/databases/collection.phtml b/app/views/console/databases/collection.phtml index 35e78b4220..19454a88db 100644 --- a/app/views/console/databases/collection.phtml +++ b/app/views/console/databases/collection.phtml @@ -607,7 +607,7 @@ $permissions = $this->getParam('permissions', null); data-success="alert,trigger,redirect" data-success-param-alert-text="Collection deleted successfully" data-success-param-trigger-events="databases.deleteCollection" - data-success-param-redirect-url="/console/databases?project={{router.params.project}}" + data-success-param-redirect-url="/console/databases?project={{router.params.project}}&databaseId={{router.params.databaseId}}" data-failure="alert" data-failure-param-alert-text="Failed to delete collection" data-failure-param-alert-classname="error"> From ec5a0b8cdef0b655c90912ae2744b12f42f3de12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 12 Sep 2022 09:02:14 +0000 Subject: [PATCH 37/52] Remove queries from listVariables; add enabled to createFunction --- app/controllers/api/functions.php | 41 +++--------- app/views/console/functions/function.phtml | 2 - .../Functions/FunctionsConsoleClientTest.php | 63 +------------------ 3 files changed, 9 insertions(+), 97 deletions(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 375ac0e453..d1edee3e38 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -67,16 +67,17 @@ App::post('/v1/functions') ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true) + ->param('enabled', true, new Boolean(), 'Is function enabled?', true) ->inject('response') ->inject('dbForProject') ->inject('events') - ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, Response $response, Database $dbForProject, Event $eventsInstance) { + ->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Event $eventsInstance) { $functionId = ($functionId == 'unique()') ? ID::unique() : $functionId; $function = $dbForProject->createDocument('functions', new Document([ '$id' => $functionId, 'execute' => $execute, - 'enabled' => true, + 'enabled' => $enabled, 'name' => $name, 'runtime' => $runtime, 'deployment' => '', @@ -424,7 +425,7 @@ App::put('/v1/functions/:functionId') ->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true) ->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true) - ->param('enabled', true, new Boolean(), 'Is collection enabled?', true) + ->param('enabled', true, new Boolean(), 'Is function enabled?', true) ->inject('response') ->inject('dbForProject') ->inject('project') @@ -1372,46 +1373,18 @@ App::get('/v1/functions/:functionId/variables') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_VARIABLE_LIST) ->param('functionId', null, new UID(), 'Function unique ID.', false) - ->param('queries', [], new Variables(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Variables::ALLOWED_ATTRIBUTES), true) - ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') - ->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject) { + ->action(function (string $functionId, Response $response, Database $dbForProject) { $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { throw new Exception(Exception::FUNCTION_NOT_FOUND); } - $queries = Query::parseQueries($queries); - - if (!empty($search)) { - $queries[] = Query::search('search', $search); - } - - // Apply internal queries - $queries[] = Query::equal('functionInternalId', [$function->getInternalId()]); - - // Get cursor document if there was a cursor query - $cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE); - $cursor = reset($cursor); - if ($cursor) { - /** @var Query $cursor */ - $variableId = $cursor->getValue(); - $cursorDocument = $dbForProject->getDocument('variables', $variableId); - - if ($cursorDocument->isEmpty()) { - throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Variable '{$variableId}' for the 'cursor' value not found."); - } - - $cursor->setValue($cursorDocument); - } - - $filterQueries = Query::groupByType($queries)['filters']; - $response->dynamic(new Document([ - 'variables' => $dbForProject->find('variables', $queries), - 'total' => $dbForProject->count('variables', $filterQueries, APP_LIMIT_COUNT), + 'variables' => $function->getAttribute('vars'), + 'total' => \count($function->getAttribute('vars')), ]), Response::MODEL_VARIABLE_LIST); }); diff --git a/app/views/console/functions/function.phtml b/app/views/console/functions/function.phtml index 235892c2db..d6290986e8 100644 --- a/app/views/console/functions/function.phtml +++ b/app/views/console/functions/function.phtml @@ -523,8 +523,6 @@ sort($patterns); data-service="functions.listVariables" data-event="load,project.update,functions.createVariable,functions.updateVariable,functions.deleteVariable" data-name="function-variables" - data-param-queries="limit(100)" - data-param-queries-cast-to="array" data-param-queries-cast-from="csv" data-param-function-id="{{router.params.id}}" data-scope="sdk">Variables diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index a6e0434f67..68b9ac46ea 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -182,74 +182,14 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, sizeof($response['body']['variables'])); + $this->assertEquals(1, $response['body']['total']); $this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']); $this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']); - $variableId = $response['body']['variables'][0]['$id']; - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ 'limit(0)' ] - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']['variables']); - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ 'offset(1)' ] - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']['variables']); - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ 'equal("key", "APP_TEST")' ] - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(1, $response['body']['variables']); - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'search' => $variableId - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(1, $response['body']['variables']); - - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ 'equal("key", "NON_EXISTING_VARIABLE")' ] - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']['variables']); - /** * Test for FAILURE */ - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ 'equal("value", "MY_SECRET")' ] - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - return $data; } @@ -403,6 +343,7 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(0, sizeof($response['body']['variables'])); + $this->assertEquals(0, $response['body']['total']); /** * Test for FAILURE From 79b57cf69634c2e73efb39cfa2da32585bf4420b Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 12 Sep 2022 19:07:08 +0000 Subject: [PATCH 38/52] 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 39/52] 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 2cbd4d6cc5f9576246474db699cc2770ec6fb30f Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 12 Sep 2022 22:48:40 +0000 Subject: [PATCH 40/52] Rename execution time to duration --- app/views/console/functions/function.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/console/functions/function.phtml b/app/views/console/functions/function.phtml index 235892c2db..d4381c03ea 100644 --- a/app/views/console/functions/function.phtml +++ b/app/views/console/functions/function.phtml @@ -416,7 +416,7 @@ sort($patterns); - + - From 1d382cc542b5a618ab06cb2eac243e8a735faad7 Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 13 Sep 2022 10:42:42 +0300 Subject: [PATCH 41/52] small fix --- app/controllers/api/functions.php | 2 +- src/Appwrite/Event/Audit.php | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index d10ed98f42..388a5cc100 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -1246,7 +1246,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') ->desc('Retry Build') ->label('scope', 'functions.write') ->label('event', 'functions.[functionId].deployments.[deploymentId].update') - ->label('audits.event', 'build.create') + ->label('audits.event', 'deployment.update') ->label('audits.resource', 'function/{request.functionId}') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'functions') diff --git a/src/Appwrite/Event/Audit.php b/src/Appwrite/Event/Audit.php index 2020548969..254f7c294a 100644 --- a/src/Appwrite/Event/Audit.php +++ b/src/Appwrite/Event/Audit.php @@ -108,29 +108,6 @@ class Audit extends Event return $this->ip; } - /** - * Set description for this audit event - * - * @param string $event - * @return self - */ - public function setEvent(string $event): self - { - $this->event = $event; - - return $this; - } - - /** - * Returns the audit event description. - * - * @return string - */ - public function getEvent(): string - { - return $this->event; - } - /** * Executes the event and sends it to the audit worker. * From 75c4662c0bd46983d234e161e6d9baa4914d262a Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 13 Sep 2022 11:08:15 +0300 Subject: [PATCH 42/52] small fix --- tests/e2e/Services/Account/AccountBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index c6f21f6b83..e8bf146316 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -363,7 +363,7 @@ trait AccountBase $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); - $this->assertContains($response['body']['logs'][2]['event'], ["account.create"]); + $this->assertContains($response['body']['logs'][2]['event'], ["user.create"]); $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); $this->assertEquals(true, DateTime::isValid($response['body']['logs'][2]['time'])); From f0626d2ee4714538e45137063702a5e1f4eb2403 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 16:05:31 +0000 Subject: [PATCH 43/52] Stop tests on failure Since tests take almost 20 minute to run, stopping tests as soon as an failure occurs will allow for faster iteration locally and also free up resources in the CI pipeline. --- phpunit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index fd59a8f236..97bec18b42 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,7 +6,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false" + stopOnFailure="true" > From f6868318e06d0b781ec33a3a8e05ae3bdc4da7fe Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 13 Sep 2022 21:54:57 +0530 Subject: [PATCH 44/52] Update docs/sdks/apple/GETTING_STARTED.md Co-authored-by: Jake Barnby --- docs/sdks/apple/GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sdks/apple/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md index de2f233189..1da041112c 100644 --- a/docs/sdks/apple/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -122,7 +122,7 @@ func main() { let account = Account(client) do { - let account = try await account.get() + let user = try await account.get() print(String(describing: user.toMap())) } catch { print(error.localizedDescription) From 8b0aa634ec1776af143764062c074d6b2b72a7c9 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 13 Sep 2022 17:01:41 +0000 Subject: [PATCH 45/52] Hide function stdout from console Because it's possible for execution stdout to end up in the wrong execution, we're going to hide the result from the UI to help avoid confusion for users while we work on resolving the problem. --- app/views/console/functions/function.phtml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/console/functions/function.phtml b/app/views/console/functions/function.phtml index d4381c03ea..d17045891b 100644 --- a/app/views/console/functions/function.phtml +++ b/app/views/console/functions/function.phtml @@ -391,9 +391,9 @@ sort($patterns); Created - Status - Trigger - Runtime + Status + Trigger + Runtime @@ -422,11 +422,11 @@ sort($patterns);
- + - +