From a52a8fa3c71be6ff6e796ca03b91eb6d5eee30b9 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 02:15:01 +0400 Subject: [PATCH 01/95] feat: added new exception class and error codes --- src/Appwrite/Extend/Exception/Codes.php | 171 ++++++++++++++++++++ src/Appwrite/Extend/Exception/Exception.php | 66 ++++++++ 2 files changed, 237 insertions(+) create mode 100644 src/Appwrite/Extend/Exception/Codes.php create mode 100644 src/Appwrite/Extend/Exception/Exception.php diff --git a/src/Appwrite/Extend/Exception/Codes.php b/src/Appwrite/Extend/Exception/Codes.php new file mode 100644 index 0000000000..2007320db3 --- /dev/null +++ b/src/Appwrite/Extend/Exception/Codes.php @@ -0,0 +1,171 @@ + [ + 'name' => Exception::TYPE_NONE, + 'description' => 'Generic error', + 'statusCode' => 500, + ], + Exception::TYPE_PROJECT_NOT_FOUND => [ + 'name' => Exception::TYPE_PROJECT_NOT_FOUND, + 'description' => 'Project not found', + 'statusCode' => 404, + ], + Exception::TYPE_PROJECT_UNKNOWN => [ + 'name' => Exception::TYPE_PROJECT_UNKNOWN, + 'description' => 'Project unknown', + 'statusCode' => 500, + ], + Exception::TYPE_INVALID_ORIGIN => [ + 'name' => Exception::TYPE_INVALID_ORIGIN, + 'description' => 'Invalid origin', + 'statusCode' => 403, + ], + Exception::TYPE_SERVICE_DISABLED => [ + 'name' => Exception::TYPE_SERVICE_DISABLED, + 'description' => 'Service disabled', + 'statusCode' => 403, + ], + Exception::TYPE_UNAUTHORIZED_SCOPE => [ + 'name' => Exception::TYPE_UNAUTHORIZED_SCOPE, + 'description' => 'Unauthorized scope', + 'statusCode' => 403, + ], + Exception::TYPE_PASSWORD_RESET_REQUIRED => [ + 'name' => Exception::TYPE_PASSWORD_RESET_REQUIRED, + 'description' => 'Password reset required', + 'statusCode' => 403, + ], + Exception::TYPE_STORAGE_ERROR => [ + 'name' => Exception::TYPE_STORAGE_ERROR, + 'description' => 'Storage error', + 'statusCode' => 500, + ], + Exception::TYPE_RATE_LIMIT_EXCEEDED => [ + 'name' => Exception::TYPE_RATE_LIMIT_EXCEEDED, + 'description' => 'Rate limit exceeded', + 'statusCode' => 429, + ], + Exception::TYPE_SMTP_DISABLED => [ + 'name' => Exception::TYPE_SMTP_DISABLED, + 'description' => 'SMTP disabled', + 'statusCode' => 500, + ], + Exception::TYPE_EMAIL_NOT_WHITELISTED => [ + 'name' => Exception::TYPE_EMAIL_NOT_WHITELISTED, + 'description' => 'Email not whitelisted', + 'statusCode' => 403, + ], + Exception::TYPE_IP_NOT_WHITELISTED => [ + 'name' => Exception::TYPE_IP_NOT_WHITELISTED, + 'description' => 'IP Address not whitelisted', + 'statusCode' => 404, + ], + Exception::TYPE_INVALID_CREDENTIALS => [ + 'name' => Exception::TYPE_INVALID_CREDENTIALS, + 'description' => 'Invalid credentials', + 'statusCode' => 404, + ], + Exception::TYPE_INVALID_TOKEN => [ + 'name' => Exception::TYPE_INVALID_TOKEN, + 'description' => 'Invalid token', + 'statusCode' => 403, + ], + Exception::TYPE_JWT_VERIFICATION_FAILED => [ + 'name' => Exception::TYPE_JWT_VERIFICATION_FAILED, + 'description' => 'Invalid refresh token', + 'statusCode' => 403, + ], + Exception::TYPE_ANONYMOUS_CONSOLE_USER => [ + 'name' => Exception::TYPE_ANONYMOUS_CONSOLE_USER, + 'description' => 'Anonymous session cannot be created for the console project.', + 'statusCode' => 403, + ], + Exception::TYPE_SESSION_NOT_FOUND => [ + 'name' => Exception::TYPE_SESSION_NOT_FOUND, + 'description' => 'Session not found', + 'statusCode' => 400, + ], + Exception::TYPE_SESSION_ALREADY_EXISTS => [ + 'name' => Exception::TYPE_SESSION_ALREADY_EXISTS, + 'description' => 'Session already exists', + 'statusCode' => 403, + ], + Exception::TYPE_USER_LIMIT_EXCEEDED => [ + 'name' => Exception::TYPE_USER_LIMIT_EXCEEDED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_USER_ALREADY_EXISTS => [ + 'name' => Exception::TYPE_USER_ALREADY_EXISTS, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_USER_BLOCKED => [ + 'name' => Exception::TYPE_USER_BLOCKED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_USER_CREATION_FAILED => [ + 'name' => Exception::TYPE_USER_CREATION_FAILED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_USER_NOT_FOUND => [ + 'name' => Exception::TYPE_USER_NOT_FOUND, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_EMAIL_ALREADY_EXISTS => [ + 'name' => Exception::TYPE_EMAIL_ALREADY_EXISTS, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_PASSWORD_MISMATCH => [ + 'name' => Exception::TYPE_PASSWORD_MISMATCH, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_AUTH_METHOD_UNSUPPORTED => [ + 'name' => Exception::TYPE_AUTH_METHOD_UNSUPPORTED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_PROVIDER_DISABLED => [ + 'name' => Exception::TYPE_PROVIDER_DISABLED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_PROVIDER_NOT_SUPPORTED => [ + 'name' => Exception::TYPE_PROVIDER_NOT_SUPPORTED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_INVALID_LOGIN_STATE_PARAMS => [ + 'name' => Exception::TYPE_INVALID_LOGIN_STATE_PARAMS, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_INVALID_SUCCESS_URL => [ + 'name' => Exception::TYPE_INVALID_SUCCESS_URL, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_INVALID_FAILURE_URL => [ + 'name' => Exception::TYPE_INVALID_FAILURE_URL, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED => [ + 'name' => Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED, + 'description' => 'Session expired', + 'statusCode' => 403, + ], + Exception::TYPE_MISSING_PROVIDER_ID => [ + 'name' => Exception::TYPE_MISSING_PROVIDER_ID, + 'description' => 'Session expired', + 'statusCode' => 403, + ] +]; \ No newline at end of file diff --git a/src/Appwrite/Extend/Exception/Exception.php b/src/Appwrite/Extend/Exception/Exception.php new file mode 100644 index 0000000000..e68e997da6 --- /dev/null +++ b/src/Appwrite/Extend/Exception/Exception.php @@ -0,0 +1,66 @@ +errorCode = $errorCode; + + parent::__construct($message, $code, $previous); + } + + /** + * @return string + */ + public function getErrorCode(): string + { + return $this->errorCode; + } +} \ No newline at end of file From 9f671cfb1894470f884016c2e1b3090d4d742d7f Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 02:20:34 +0400 Subject: [PATCH 02/95] feat: move error codes to config --- .../Extend/Exception/Codes.php => app/config/errorCodes.php | 4 ++++ src/Appwrite/Extend/{Exception => }/Exception.php | 0 2 files changed, 4 insertions(+) rename src/Appwrite/Extend/Exception/Codes.php => app/config/errorCodes.php (98%) rename src/Appwrite/Extend/{Exception => }/Exception.php (100%) diff --git a/src/Appwrite/Extend/Exception/Codes.php b/app/config/errorCodes.php similarity index 98% rename from src/Appwrite/Extend/Exception/Codes.php rename to app/config/errorCodes.php index 2007320db3..11bb352878 100644 --- a/src/Appwrite/Extend/Exception/Codes.php +++ b/app/config/errorCodes.php @@ -1,5 +1,9 @@ Date: Sun, 30 Jan 2022 02:47:35 +0400 Subject: [PATCH 03/95] feat: load error codes in exception --- app/init.php | 1 + src/Appwrite/Extend/Exception.php | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/app/init.php b/app/init.php index d591d1ddbd..cd0ffc8a10 100644 --- a/app/init.php +++ b/app/init.php @@ -127,6 +127,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); */ Config::load('events', __DIR__.'/config/events.php'); Config::load('auth', __DIR__.'/config/auth.php'); +Config::load('errorCodes', __DIR__.'/config/errorCodes.php'); Config::load('providers', __DIR__.'/config/providers.php'); Config::load('platforms', __DIR__.'/config/platforms.php'); Config::load('collections', __DIR__.'/config/collections.php'); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index e68e997da6..26a4d41792 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -2,6 +2,8 @@ namespace Appwrite\Extend\Exception; +use Utopia\Config\Config; + class Exception extends \Exception { /** @@ -49,10 +51,20 @@ class Exception extends \Exception private $errorCode = ''; + static $codes = Config::getParam('errorCodes', []); + public function __construct(string $message, int $code = 0, string $errorCode = Exception::TYPE_NONE, \Throwable $previous = null) { + if (!isset(self::$codes)) { + throw new \Exception('Error codes not found', 500); + } + $this->errorCode = $errorCode; + if (isset(self::$codes[$errorCode])) { + $this->$message = self::$codes[$errorCode]['statusCode']; + } + parent::__construct($message, $code, $previous); } From ecb4f97a720d58a0b3a1820f9334a082c0c45c3a Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 02:49:52 +0400 Subject: [PATCH 04/95] fix: exception namespace --- src/Appwrite/Extend/Exception.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 26a4d41792..138d9aa3e9 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -1,6 +1,6 @@ Date: Sun, 30 Jan 2022 02:50:07 +0400 Subject: [PATCH 05/95] fix: exception namespace --- app/config/errorCodes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index 11bb352878..f904d6e794 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -4,7 +4,7 @@ * List of server wide error codes and their respective messages. */ -use Appwrite\Extend\Exception\Exception; +use Appwrite\Extend\Exception; return [ Exception::TYPE_NONE => [ From c4b5f59b1b9b462a300cef3774b14d3db2b6cabf Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 02:53:39 +0400 Subject: [PATCH 06/95] fix: bugs in exception class --- src/Appwrite/Extend/Exception.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 138d9aa3e9..a2a4dbfb62 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -51,20 +51,10 @@ class Exception extends \Exception private $errorCode = ''; - static $codes = Config::getParam('errorCodes', []); - public function __construct(string $message, int $code = 0, string $errorCode = Exception::TYPE_NONE, \Throwable $previous = null) { - if (!isset(self::$codes)) { - throw new \Exception('Error codes not found', 500); - } - $this->errorCode = $errorCode; - if (isset(self::$codes[$errorCode])) { - $this->$message = self::$codes[$errorCode]['statusCode']; - } - parent::__construct($message, $code, $previous); } From df55cf4e390c6697b59fe1faa3ea8820196bb72f Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 03:05:23 +0400 Subject: [PATCH 07/95] fix: add description --- app/config/errorCodes.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index f904d6e794..b8b2d99a64 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -7,14 +7,9 @@ use Appwrite\Extend\Exception; return [ - Exception::TYPE_NONE => [ - 'name' => Exception::TYPE_NONE, - 'description' => 'Generic error', - 'statusCode' => 500, - ], Exception::TYPE_PROJECT_NOT_FOUND => [ 'name' => Exception::TYPE_PROJECT_NOT_FOUND, - 'description' => 'Project not found', + 'description' => 'The requested project could not be found. Please check the value of the `X-Appwrite-Project` header to ensure the correct project ID is being used.', 'statusCode' => 404, ], Exception::TYPE_PROJECT_UNKNOWN => [ From 8264a8fcd1024448fb1bd0fd5a17330944f83d51 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 03:08:56 +0400 Subject: [PATCH 08/95] feat: improve description --- app/config/errorCodes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index b8b2d99a64..5cf9043baa 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -9,13 +9,13 @@ use Appwrite\Extend\Exception; return [ Exception::TYPE_PROJECT_NOT_FOUND => [ 'name' => Exception::TYPE_PROJECT_NOT_FOUND, - 'description' => 'The requested project could not be found. Please check the value of the `X-Appwrite-Project` header to ensure the correct project ID is being used.', + 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', 'statusCode' => 404, ], Exception::TYPE_PROJECT_UNKNOWN => [ 'name' => Exception::TYPE_PROJECT_UNKNOWN, - 'description' => 'Project unknown', - 'statusCode' => 500, + 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', + 'statusCode' => 400, ], Exception::TYPE_INVALID_ORIGIN => [ 'name' => Exception::TYPE_INVALID_ORIGIN, From 6a0b3c328b2fcd9d1351f61d450f4c4122bc9f35 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 03:12:34 +0400 Subject: [PATCH 09/95] feat: add more descriptions --- app/config/errorCodes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index 5cf9043baa..fd080e4768 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -19,13 +19,13 @@ return [ ], Exception::TYPE_INVALID_ORIGIN => [ 'name' => Exception::TYPE_INVALID_ORIGIN, - 'description' => 'Invalid origin', + 'description' => 'The request originated from a non-whitelisted origin. If you trust this origin, please add it as a platform in the Appwrite console.', 'statusCode' => 403, ], Exception::TYPE_SERVICE_DISABLED => [ 'name' => Exception::TYPE_SERVICE_DISABLED, - 'description' => 'Service disabled', - 'statusCode' => 403, + 'description' => 'The requested service is disabled. You can toggle the service from the Appwrite console or by contacting the project owner.', + 'statusCode' => 503, ], Exception::TYPE_UNAUTHORIZED_SCOPE => [ 'name' => Exception::TYPE_UNAUTHORIZED_SCOPE, From aedded86de1156aec0eb8068a8863fe619e33f37 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 03:13:55 +0400 Subject: [PATCH 10/95] feat: add more desctiptions --- app/config/errorCodes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index fd080e4768..494020840c 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -29,8 +29,8 @@ return [ ], Exception::TYPE_UNAUTHORIZED_SCOPE => [ 'name' => Exception::TYPE_UNAUTHORIZED_SCOPE, - 'description' => 'Unauthorized scope', - 'statusCode' => 403, + 'description' => 'The current user is not authorized to access the requested resource.', + 'statusCode' => 401, ], Exception::TYPE_PASSWORD_RESET_REQUIRED => [ 'name' => Exception::TYPE_PASSWORD_RESET_REQUIRED, From 506c19eb01fa03be84ccb2bae2512c9917a9ca52 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 30 Jan 2022 03:27:29 +0400 Subject: [PATCH 11/95] feat: add more desctiptions --- app/config/errorCodes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index 494020840c..c36645ddb4 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -104,12 +104,12 @@ return [ ], Exception::TYPE_USER_BLOCKED => [ 'name' => Exception::TYPE_USER_BLOCKED, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'The current user has been blocked. Please contact the administrator for more information.', + 'statusCode' => 401, ], Exception::TYPE_USER_CREATION_FAILED => [ 'name' => Exception::TYPE_USER_CREATION_FAILED, - 'description' => 'Session expired', + 'description' => 'Failed to create user.', 'statusCode' => 403, ], Exception::TYPE_USER_NOT_FOUND => [ From f042c00b20f1a711cb4e1f3bf7e2bf6f7b2c366b Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 31 Jan 2022 02:44:47 +0400 Subject: [PATCH 12/95] feat: add new exceptions to accounts api --- app/config/errorCodes.php | 104 +++++++++++++++--------------- app/controllers/api/account.php | 86 ++++++++++++------------ src/Appwrite/Extend/Exception.php | 4 +- 3 files changed, 97 insertions(+), 97 deletions(-) diff --git a/app/config/errorCodes.php b/app/config/errorCodes.php index c36645ddb4..8b568de0a3 100644 --- a/app/config/errorCodes.php +++ b/app/config/errorCodes.php @@ -24,7 +24,7 @@ return [ ], Exception::TYPE_SERVICE_DISABLED => [ 'name' => Exception::TYPE_SERVICE_DISABLED, - 'description' => 'The requested service is disabled. You can toggle the service from the Appwrite console or by contacting the project owner.', + 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', 'statusCode' => 503, ], Exception::TYPE_UNAUTHORIZED_SCOPE => [ @@ -34,8 +34,8 @@ return [ ], Exception::TYPE_PASSWORD_RESET_REQUIRED => [ 'name' => Exception::TYPE_PASSWORD_RESET_REQUIRED, - 'description' => 'Password reset required', - 'statusCode' => 403, + 'description' => 'The current user requires a password reset.', + 'statusCode' => 412, ], Exception::TYPE_STORAGE_ERROR => [ 'name' => Exception::TYPE_STORAGE_ERROR, @@ -44,33 +44,33 @@ return [ ], Exception::TYPE_RATE_LIMIT_EXCEEDED => [ 'name' => Exception::TYPE_RATE_LIMIT_EXCEEDED, - 'description' => 'Rate limit exceeded', + 'description' => 'Rate limit for the current endpoint has been exceeded. ', 'statusCode' => 429, ], Exception::TYPE_SMTP_DISABLED => [ 'name' => Exception::TYPE_SMTP_DISABLED, - 'description' => 'SMTP disabled', - 'statusCode' => 500, + 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project ', + 'statusCode' => 503, ], Exception::TYPE_EMAIL_NOT_WHITELISTED => [ 'name' => Exception::TYPE_EMAIL_NOT_WHITELISTED, - 'description' => 'Email not whitelisted', - 'statusCode' => 403, + 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', + 'statusCode' => 401, ], Exception::TYPE_IP_NOT_WHITELISTED => [ 'name' => Exception::TYPE_IP_NOT_WHITELISTED, - 'description' => 'IP Address not whitelisted', - 'statusCode' => 404, + 'description' => 'The user\'s IP address is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_IPS environment variable of your Appwrite server.', + 'statusCode' => 401, ], Exception::TYPE_INVALID_CREDENTIALS => [ 'name' => Exception::TYPE_INVALID_CREDENTIALS, - 'description' => 'Invalid credentials', - 'statusCode' => 404, + 'description' => 'Invalid credentials. Please check the email and password.', + 'statusCode' => 401, ], Exception::TYPE_INVALID_TOKEN => [ 'name' => Exception::TYPE_INVALID_TOKEN, - 'description' => 'Invalid token', - 'statusCode' => 403, + 'description' => 'The used token is invalid.', + 'statusCode' => 401, ], Exception::TYPE_JWT_VERIFICATION_FAILED => [ 'name' => Exception::TYPE_JWT_VERIFICATION_FAILED, @@ -80,91 +80,91 @@ return [ Exception::TYPE_ANONYMOUS_CONSOLE_USER => [ 'name' => Exception::TYPE_ANONYMOUS_CONSOLE_USER, 'description' => 'Anonymous session cannot be created for the console project.', - 'statusCode' => 403, + 'statusCode' => 401, ], Exception::TYPE_SESSION_NOT_FOUND => [ 'name' => Exception::TYPE_SESSION_NOT_FOUND, - 'description' => 'Session not found', - 'statusCode' => 400, + 'description' => 'No valid session found.', + 'statusCode' => 404, ], Exception::TYPE_SESSION_ALREADY_EXISTS => [ 'name' => Exception::TYPE_SESSION_ALREADY_EXISTS, - 'description' => 'Session already exists', - 'statusCode' => 403, + 'description' => 'Cannot create anonymous session when there is an active session.', + 'statusCode' => 401, ], Exception::TYPE_USER_LIMIT_EXCEEDED => [ 'name' => Exception::TYPE_USER_LIMIT_EXCEEDED, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'The current project has exceeded the maximum number of users. Please check your user limit in the Appwrite console.', + 'statusCode' => 501, ], Exception::TYPE_USER_ALREADY_EXISTS => [ 'name' => Exception::TYPE_USER_ALREADY_EXISTS, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'A user with the same email ID already exists in your project.', + 'statusCode' => 409, ], Exception::TYPE_USER_BLOCKED => [ 'name' => Exception::TYPE_USER_BLOCKED, - 'description' => 'The current user has been blocked. Please contact the administrator for more information.', + 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', 'statusCode' => 401, ], Exception::TYPE_USER_CREATION_FAILED => [ 'name' => Exception::TYPE_USER_CREATION_FAILED, - 'description' => 'Failed to create user.', - 'statusCode' => 403, + 'description' => 'There was an internal server error while creating the user.', + 'statusCode' => 500, ], Exception::TYPE_USER_NOT_FOUND => [ 'name' => Exception::TYPE_USER_NOT_FOUND, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'User with the requested ID could not be found.', + 'statusCode' => 404, ], Exception::TYPE_EMAIL_ALREADY_EXISTS => [ 'name' => Exception::TYPE_EMAIL_ALREADY_EXISTS, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'Another user with the same email already exists in the current project.', + 'statusCode' => 409, ], Exception::TYPE_PASSWORD_MISMATCH => [ 'name' => Exception::TYPE_PASSWORD_MISMATCH, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'Passwords do not match. Please recheck.', + 'statusCode' => 400, ], Exception::TYPE_AUTH_METHOD_UNSUPPORTED => [ 'name' => Exception::TYPE_AUTH_METHOD_UNSUPPORTED, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'The requested authentication method is either disabled or unsupported.', + 'statusCode' => 501, ], Exception::TYPE_PROVIDER_DISABLED => [ 'name' => Exception::TYPE_PROVIDER_DISABLED, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'The chosen OAuth provider is disabled. Please contact your project administrator for more information.', + 'statusCode' => 412, ], - Exception::TYPE_PROVIDER_NOT_SUPPORTED => [ - 'name' => Exception::TYPE_PROVIDER_NOT_SUPPORTED, - 'description' => 'Session expired', - 'statusCode' => 403, + Exception::TYPE_PROVIDER_UNSUPPORTED => [ + 'name' => Exception::TYPE_PROVIDER_UNSUPPORTED, + 'description' => 'The chosen OAuth provider is unsupported.', + 'statusCode' => 501, ], Exception::TYPE_INVALID_LOGIN_STATE_PARAMS => [ 'name' => Exception::TYPE_INVALID_LOGIN_STATE_PARAMS, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'Failed to parse the login state params from the OAuth provider.', + 'statusCode' => 500, ], Exception::TYPE_INVALID_SUCCESS_URL => [ 'name' => Exception::TYPE_INVALID_SUCCESS_URL, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'Invalid URL received for OAuth success redirect.', + 'statusCode' => 400, ], Exception::TYPE_INVALID_FAILURE_URL => [ 'name' => Exception::TYPE_INVALID_FAILURE_URL, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'Invalid URL received for OAuth failure redirect.', + 'statusCode' => 400, ], Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED => [ 'name' => Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED, - 'description' => 'Session expired', - 'statusCode' => 403, + 'description' => 'Failed to obtain access token from the OAuth provider.', + 'statusCode' => 500, ], - Exception::TYPE_MISSING_PROVIDER_ID => [ - 'name' => Exception::TYPE_MISSING_PROVIDER_ID, - 'description' => 'Session expired', - 'statusCode' => 403, + Exception::TYPE_MISSING_USER_ID => [ + 'name' => Exception::TYPE_MISSING_USER_ID, + 'description' => 'Failed to obtain user id from the OAuth provider.', + 'statusCode' => 400, ] ]; \ No newline at end of file diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 19c8cf3b27..d4b7182be5 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -20,7 +20,7 @@ use Utopia\Database\Exception\Duplicate; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; use Utopia\Validator\Range; @@ -68,11 +68,11 @@ App::post('/v1/account') $whitelistIPs = $project->getAttribute('authWhitelistIPs'); if (!empty($whitelistEmails) && !\in_array($email, $whitelistEmails)) { - throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401); + throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401, Exception::TYPE_EMAIL_NOT_WHITELISTED); } if (!empty($whitelistIPs) && !\in_array($request->getIP(), $whitelistIPs)) { - throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401); + throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401, Exception::TYPE_IP_NOT_WHITELISTED); } } @@ -84,7 +84,7 @@ App::post('/v1/account') ], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); } } @@ -110,7 +110,7 @@ App::post('/v1/account') 'deleted' => false ]))); } catch (Duplicate $th) { - throw new Exception('Account already exists', 409); + throw new Exception('Account already exists', 409, Exception::TYPE_USER_ALREADY_EXISTS); } Authorization::unsetRole('role:' . Auth::USER_ROLE_GUEST); @@ -175,11 +175,11 @@ App::post('/v1/account/sessions') ->setParam('resource', 'user/'.($profile ? $profile->getId() : '')) ; - throw new Exception('Invalid credentials', 401); // Wrong password or username + throw new Exception('Invalid credentials', 401, Exception::TYPE_INVALID_CREDENTIALS); // Wrong password or username } if (false === $profile->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401); // User is in status blocked + throw new Exception('Invalid credentials. User is blocked', 401, Exception::TYPE_USER_BLOCKED); // User is in status blocked } $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -282,13 +282,13 @@ App::get('/v1/account/sessions/oauth2/:provider') } if (empty($appId) || empty($appSecret)) { - throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412); + throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::TYPE_PROVIDER_DISABLED); } $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); if (!\class_exists($className)) { - throw new Exception('Provider is not supported', 501); + throw new Exception('Provider is not supported', 501, Exception::TYPE_PROVIDER_UNSUPPORTED); } if(empty($success)) { @@ -406,7 +406,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); if (!\class_exists($className)) { - throw new Exception('Provider is not supported', 501); + throw new Exception('Provider is not supported', 501, Exception::TYPE_PROVIDER_UNSUPPORTED); } $oauth2 = new $className($appId, $appSecret, $callback); @@ -415,18 +415,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') try { $state = \array_merge($defaultState, $oauth2->parseState($state)); } catch (\Exception$exception) { - throw new Exception('Failed to parse login state params as passed from OAuth2 provider'); + throw new Exception('Failed to parse login state params as passed from OAuth2 provider', 500, Exception::TYPE_INVALID_LOGIN_STATE_PARAMS); } } else { $state = $defaultState; } if (!$validateURL->isValid($state['success'])) { - throw new Exception('Invalid redirect URL for success login', 400); + throw new Exception('Invalid redirect URL for success login', 400, Exception::TYPE_INVALID_SUCCESS_URL); } if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) { - throw new Exception('Invalid redirect URL for failure login', 400); + throw new Exception('Invalid redirect URL for failure login', 400, Exception::TYPE_INVALID_FAILURE_URL); } $state['failure'] = null; @@ -437,7 +437,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response->redirect($state['failure'], 301, 0); } - throw new Exception('Failed to obtain access token'); + throw new Exception('Failed to obtain access token', 500, Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED); } $oauth2ID = $oauth2->getUserID($accessToken); @@ -447,7 +447,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response->redirect($state['failure'], 301, 0); } - throw new Exception('Missing ID from OAuth2 provider', 400); + throw new Exception('Missing ID from OAuth2 provider', 400, Exception::TYPE_MISSING_USER_ID); } $sessions = $user->getAttribute('sessions', []); @@ -482,7 +482,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $sum = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); } } @@ -508,13 +508,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'deleted' => false ]))); } catch (Duplicate $th) { - throw new Exception('Account already exists', 409); + throw new Exception('Account already exists', 409, Exception::TYPE_USER_ALREADY_EXISTS); } } } if (false === $user->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401); // User is in status blocked + throw new Exception('Invalid credentials. User is blocked', 401, Exception::TYPE_USER_BLOCKED); // User is in status blocked } // Create session token, verify user account and update OAuth2 ID and Access Token @@ -637,7 +637,7 @@ App::post('/v1/account/sessions/magic-url') /** @var Appwrite\Event\Event $mails */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503); + throw new Exception('SMTP Disabled', 503, Exception::TYPE_SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -655,7 +655,7 @@ App::post('/v1/account/sessions/magic-url') ], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); } } @@ -705,7 +705,7 @@ App::post('/v1/account/sessions/magic-url') $user = $dbForProject->updateDocument('users', $user->getId(), $user); if (false === $user) { - throw new Exception('Failed to save user to DB', 500); + throw new Exception('Failed to save user to DB', 500, Exception::TYPE_USER_CREATION_FAILED); } if(empty($url)) { @@ -783,13 +783,13 @@ App::put('/v1/account/sessions/magic-url') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); } $token = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_MAGIC_URL, $secret); if (!$token) { - throw new Exception('Invalid login token', 401); + throw new Exception('Invalid login token', 401, Exception::TYPE_INVALID_TOKEN); } $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -839,7 +839,7 @@ App::put('/v1/account/sessions/magic-url') $user = $dbForProject->updateDocument('users', $user->getId(), $user); if (false === $user) { - throw new Exception('Failed saving user to DB', 500); + throw new Exception('Failed saving user to DB', 500, Exception::TYPE_USER_CREATION_FAILED); } $audits @@ -912,11 +912,11 @@ App::post('/v1/account/sessions/anonymous') $protocol = $request->getProtocol(); if ('console' === $project->getId()) { - throw new Exception('Failed to create anonymous user.', 401); + throw new Exception('Failed to create anonymous user.', 401, Exception::TYPE_ANONYMOUS_CONSOLE_USER); } if (!$user->isEmpty()) { - throw new Exception('Cannot create an anonymous user when logged in.', 401); + throw new Exception('Cannot create an anonymous user when logged in.', 401, Exception::TYPE_SESSION_ALREADY_EXISTS); } $limit = $project->getAttribute('auths', [])['limit'] ?? 0; @@ -927,7 +927,7 @@ App::post('/v1/account/sessions/anonymous') ], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); } } @@ -1051,7 +1051,7 @@ App::post('/v1/account/jwt') } if ($current->isEmpty()) { - throw new Exception('No valid session found', 401); + throw new Exception('No valid session found', 401, Exception::TYPE_SESSION_NOT_FOUND); } $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. @@ -1296,7 +1296,7 @@ App::get('/v1/account/sessions/:sessionId') } } - throw new Exception('Session not found', 404); + throw new Exception('Session not found', 404, Exception::TYPE_SESSION_NOT_FOUND); }); App::patch('/v1/account/name') @@ -1370,7 +1370,7 @@ App::patch('/v1/account/password') // Check old password only if its an existing user. if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password - throw new Exception('Invalid credentials', 401); + throw new Exception('Invalid credentials', 401, Exception::TYPE_INVALID_CREDENTIALS); } $user = $dbForProject->updateDocument('users', $user->getId(), $user @@ -1422,14 +1422,14 @@ App::patch('/v1/account/email') !$isAnonymousUser && !Auth::passwordVerify($password, $user->getAttribute('password')) ) { // Double check user password - throw new Exception('Invalid credentials', 401); + throw new Exception('Invalid credentials', 401, Exception::TYPE_INVALID_CREDENTIALS); } $email = \strtolower($email); $profile = $dbForProject->findOne('users', [new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address if ($profile) { - throw new Exception('User already registered', 409); + throw new Exception('User already registered', 409, Exception::TYPE_USER_ALREADY_EXISTS); } try { @@ -1440,7 +1440,7 @@ App::patch('/v1/account/email') ->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')])) ); } catch(Duplicate $th) { - throw new Exception('Email already exists', 409); + throw new Exception('Email already exists', 409, Exception::TYPE_EMAIL_ALREADY_EXISTS); } $audits @@ -1644,7 +1644,7 @@ App::delete('/v1/account/sessions/:sessionId') } } - throw new Exception('Session not found', 404); + throw new Exception('Session not found', 404, Exception::TYPE_SESSION_NOT_FOUND); }); App::delete('/v1/account/sessions') @@ -1764,7 +1764,7 @@ App::post('/v1/account/recovery') /** @var Appwrite\Stats\Stats $usage */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503); + throw new Exception('SMTP Disabled', 503, Exception::TYPE_SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -1775,11 +1775,11 @@ App::post('/v1/account/recovery') $profile = $dbForProject->findOne('users', [new Query('deleted', Query::TYPE_EQUAL, [false]), new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address if (!$profile) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); } if (false === $profile->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401); + throw new Exception('Invalid credentials. User is blocked', 401, Exception::TYPE_USER_BLOCKED); } $expire = \time() + Auth::TOKEN_EXPIRATION_RECOVERY; @@ -1870,20 +1870,20 @@ App::put('/v1/account/recovery') /** @var Appwrite\Stats\Stats $usage */ if ($password !== $passwordAgain) { - throw new Exception('Passwords must match', 400); + throw new Exception('Passwords must match', 400, Exception::TYPE_PASSWORD_MISMATCH); } $profile = $dbForProject->getDocument('users', $userId); if ($profile->isEmpty() || $profile->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); } $tokens = $profile->getAttribute('tokens', []); $recovery = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_RECOVERY, $secret); if (!$recovery) { - throw new Exception('Invalid recovery token', 401); + throw new Exception('Invalid recovery token', 401, Exception::TYPE_INVALID_TOKEN); } Authorization::setRole('user:' . $profile->getId()); @@ -1957,7 +1957,7 @@ App::post('/v1/account/verification') /** @var Appwrite\Stats\Stats $usage */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503); + throw new Exception('SMTP Disabled', 503, Exception::TYPE_SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -2055,14 +2055,14 @@ App::put('/v1/account/verification') $profile = $dbForProject->getDocument('users', $userId); if ($profile->isEmpty()) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); } $tokens = $profile->getAttribute('tokens', []); $verification = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_VERIFICATION, $secret); if (!$verification) { - throw new Exception('Invalid verification token', 401); + throw new Exception('Invalid verification token', 401, Exception::TYPE_INVALID_TOKEN); } Authorization::setRole('user:' . $profile->getId()); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index a2a4dbfb62..686289eb13 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -42,12 +42,12 @@ class Exception extends \Exception /** OAuth **/ const TYPE_PROVIDER_DISABLED = 'provider_disabled'; - const TYPE_PROVIDER_NOT_SUPPORTED = 'provider_not_supported'; + const TYPE_PROVIDER_UNSUPPORTED = 'provider_unsupported'; const TYPE_INVALID_LOGIN_STATE_PARAMS = 'invalid_login_state_params'; const TYPE_INVALID_SUCCESS_URL = 'invalid_success_url'; const TYPE_INVALID_FAILURE_URL = 'invalid_failure_url'; const TYPE_OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; - const TYPE_MISSING_PROVIDER_ID = 'missing_provider_id'; + const TYPE_MISSING_USER_ID = 'missing_user_id'; private $errorCode = ''; From 5795733f6a67f6b846e529da810f201fb74f06fd Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 1 Feb 2022 03:59:32 +0400 Subject: [PATCH 13/95] Update app/init.php Co-authored-by: Eldad A. Fux --- app/init.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/init.php b/app/init.php index cd0ffc8a10..7327ab226f 100644 --- a/app/init.php +++ b/app/init.php @@ -127,7 +127,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); */ Config::load('events', __DIR__.'/config/events.php'); Config::load('auth', __DIR__.'/config/auth.php'); -Config::load('errorCodes', __DIR__.'/config/errorCodes.php'); +Config::load('errors', __DIR__.'/config/errors.php'); Config::load('providers', __DIR__.'/config/providers.php'); Config::load('platforms', __DIR__.'/config/platforms.php'); Config::load('collections', __DIR__.'/config/collections.php'); From 6f4b53ad725f6b2591981b9cc4151885b4f4a378 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 1 Feb 2022 12:39:07 +0400 Subject: [PATCH 14/95] feat: fix tests --- app/config/{errorCodes.php => errors.php} | 0 src/Appwrite/Extend/Exception.php | 36 +++++++++++++++----- src/Appwrite/Utopia/Response/Model/Error.php | 6 ++++ 3 files changed, 33 insertions(+), 9 deletions(-) rename app/config/{errorCodes.php => errors.php} (100%) diff --git a/app/config/errorCodes.php b/app/config/errors.php similarity index 100% rename from app/config/errorCodes.php rename to app/config/errors.php diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 686289eb13..f96621049c 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -25,20 +25,11 @@ class Exception extends \Exception /** Users **/ const TYPE_EMAIL_NOT_WHITELISTED = 'email_not_whitelisted'; const TYPE_IP_NOT_WHITELISTED = 'ip_not_whitelisted'; - const TYPE_INVALID_CREDENTIALS = 'invalid_credentials'; const TYPE_INVALID_TOKEN = 'invalid_token'; const TYPE_JWT_VERIFICATION_FAILED = 'jwt_verification_failed'; const TYPE_ANONYMOUS_CONSOLE_USER = 'anonymous_console_user'; const TYPE_SESSION_NOT_FOUND = 'session_not_found'; const TYPE_SESSION_ALREADY_EXISTS = 'session_already_exists'; - const TYPE_USER_LIMIT_EXCEEDED = 'user_limit_exceeded'; - const TYPE_USER_ALREADY_EXISTS = 'user_already_exists'; - const TYPE_USER_BLOCKED = 'user_blocked'; - const TYPE_USER_CREATION_FAILED = 'user_creation_failed'; - const TYPE_USER_NOT_FOUND = 'user_not_found'; - const TYPE_EMAIL_ALREADY_EXISTS = 'email_already_exists'; - const TYPE_PASSWORD_MISMATCH = 'password_mismatch'; - const TYPE_AUTH_METHOD_UNSUPPORTED = 'auth_method_unsupported'; /** OAuth **/ const TYPE_PROVIDER_DISABLED = 'provider_disabled'; @@ -49,6 +40,33 @@ class Exception extends \Exception const TYPE_OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; const TYPE_MISSING_USER_ID = 'missing_user_id'; + + /** + * Naming the error types based on the following convention + * _ + * Appwrite has the follwing entities: + * - Users + * - Projects + * - Sessions + * - Teams + * - Memberships + * - Files + * - Functions + * - Deployments + * - Executions + */ + + /** Users */ + const USER_COUNT_EXCEEDED = 'user_count_exceeded'; + const USER_ALREADY_EXISTS = 'user_already_exists'; + const USER_BLOCKED = 'user_blocked'; + const USER_CREATION_FAILED = 'user_creation_failed'; + const USER_NOT_FOUND = 'user_not_found'; + const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; + const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; + const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; + const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; + private $errorCode = ''; public function __construct(string $message, int $code = 0, string $errorCode = Exception::TYPE_NONE, \Throwable $previous = null) diff --git a/src/Appwrite/Utopia/Response/Model/Error.php b/src/Appwrite/Utopia/Response/Model/Error.php index 507b252093..e12e0bd42c 100644 --- a/src/Appwrite/Utopia/Response/Model/Error.php +++ b/src/Appwrite/Utopia/Response/Model/Error.php @@ -22,6 +22,12 @@ class Error extends Model 'default' => '', 'example' => '404', ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Error type.', + 'default' => '', + 'example' => 'not_found', + ]) ->addRule('version', [ 'type' => self::TYPE_STRING, 'description' => 'Server version number.', From b16faed83a5cf42b8ab63afd59f22bd76ef5722a Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:49:01 +0400 Subject: [PATCH 15/95] feat: update error codes in users API --- app/config/errors.php | 174 ++++++++++++++---------------- app/controllers/api/users.php | 34 +++--- app/controllers/general.php | 18 ++-- app/controllers/shared/api.php | 18 ++-- src/Appwrite/Extend/Exception.php | 64 +++++------ 5 files changed, 142 insertions(+), 166 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 8b568de0a3..b85841aa6e 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -7,163 +7,145 @@ use Appwrite\Extend\Exception; return [ - Exception::TYPE_PROJECT_NOT_FOUND => [ - 'name' => Exception::TYPE_PROJECT_NOT_FOUND, - 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'statusCode' => 404, - ], - Exception::TYPE_PROJECT_UNKNOWN => [ - 'name' => Exception::TYPE_PROJECT_UNKNOWN, - 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'statusCode' => 400, - ], - Exception::TYPE_INVALID_ORIGIN => [ - 'name' => Exception::TYPE_INVALID_ORIGIN, + /** General Errors */ + Exception::UNKNOWN_ORIGIN => [ + 'name' => Exception::UNKNOWN_ORIGIN, 'description' => 'The request originated from a non-whitelisted origin. If you trust this origin, please add it as a platform in the Appwrite console.', 'statusCode' => 403, ], - Exception::TYPE_SERVICE_DISABLED => [ - 'name' => Exception::TYPE_SERVICE_DISABLED, + Exception::SERVICE_DISABLED => [ + 'name' => Exception::SERVICE_DISABLED, 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', 'statusCode' => 503, ], - Exception::TYPE_UNAUTHORIZED_SCOPE => [ - 'name' => Exception::TYPE_UNAUTHORIZED_SCOPE, - 'description' => 'The current user is not authorized to access the requested resource.', + Exception::UNAUTHORIZED_SCOPE => [ + 'name' => Exception::UNAUTHORIZED_SCOPE, + 'description' => 'The current user or API key does not have the required scopes to access the requested resource.', 'statusCode' => 401, ], - Exception::TYPE_PASSWORD_RESET_REQUIRED => [ - 'name' => Exception::TYPE_PASSWORD_RESET_REQUIRED, - 'description' => 'The current user requires a password reset.', - 'statusCode' => 412, - ], - Exception::TYPE_STORAGE_ERROR => [ - 'name' => Exception::TYPE_STORAGE_ERROR, + Exception::STORAGE_ERROR => [ + 'name' => Exception::STORAGE_ERROR, 'description' => 'Storage error', 'statusCode' => 500, ], - Exception::TYPE_RATE_LIMIT_EXCEEDED => [ - 'name' => Exception::TYPE_RATE_LIMIT_EXCEEDED, - 'description' => 'Rate limit for the current endpoint has been exceeded. ', + Exception::RATE_LIMIT_EXCEEDED => [ + 'name' => Exception::RATE_LIMIT_EXCEEDED, + 'description' => 'Rate limit for the current endpoint has been exceeded. Please try again after some time.', 'statusCode' => 429, ], - Exception::TYPE_SMTP_DISABLED => [ - 'name' => Exception::TYPE_SMTP_DISABLED, + Exception::SMTP_DISABLED => [ + 'name' => Exception::SMTP_DISABLED, 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project ', 'statusCode' => 503, ], - Exception::TYPE_EMAIL_NOT_WHITELISTED => [ - 'name' => Exception::TYPE_EMAIL_NOT_WHITELISTED, - 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', - 'statusCode' => 401, - ], - Exception::TYPE_IP_NOT_WHITELISTED => [ - 'name' => Exception::TYPE_IP_NOT_WHITELISTED, - 'description' => 'The user\'s IP address is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_IPS environment variable of your Appwrite server.', - 'statusCode' => 401, - ], - Exception::TYPE_INVALID_CREDENTIALS => [ - 'name' => Exception::TYPE_INVALID_CREDENTIALS, - 'description' => 'Invalid credentials. Please check the email and password.', - 'statusCode' => 401, - ], - Exception::TYPE_INVALID_TOKEN => [ - 'name' => Exception::TYPE_INVALID_TOKEN, - 'description' => 'The used token is invalid.', - 'statusCode' => 401, - ], - Exception::TYPE_JWT_VERIFICATION_FAILED => [ - 'name' => Exception::TYPE_JWT_VERIFICATION_FAILED, - 'description' => 'Invalid refresh token', - 'statusCode' => 403, - ], - Exception::TYPE_ANONYMOUS_CONSOLE_USER => [ - 'name' => Exception::TYPE_ANONYMOUS_CONSOLE_USER, - 'description' => 'Anonymous session cannot be created for the console project.', - 'statusCode' => 401, - ], - Exception::TYPE_SESSION_NOT_FOUND => [ - 'name' => Exception::TYPE_SESSION_NOT_FOUND, - 'description' => 'No valid session found.', + + /** Project Errors */ + Exception::PROJECT_NOT_FOUND => [ + 'name' => Exception::PROJECT_NOT_FOUND, + 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', 'statusCode' => 404, ], - Exception::TYPE_SESSION_ALREADY_EXISTS => [ - 'name' => Exception::TYPE_SESSION_ALREADY_EXISTS, - 'description' => 'Cannot create anonymous session when there is an active session.', - 'statusCode' => 401, + Exception::PROJECT_UNKNOWN => [ + 'name' => Exception::PROJECT_UNKNOWN, + 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', + 'statusCode' => 400, ], - Exception::TYPE_USER_LIMIT_EXCEEDED => [ - 'name' => Exception::TYPE_USER_LIMIT_EXCEEDED, + + /** User Errors */ + Exception::USER_COUNT_EXCEEDED => [ + 'name' => Exception::USER_COUNT_EXCEEDED, 'description' => 'The current project has exceeded the maximum number of users. Please check your user limit in the Appwrite console.', 'statusCode' => 501, ], - Exception::TYPE_USER_ALREADY_EXISTS => [ - 'name' => Exception::TYPE_USER_ALREADY_EXISTS, + Exception::USER_EMAIL_NOT_WHITELISTED => [ + 'name' => Exception::USER_EMAIL_NOT_WHITELISTED, + 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', + 'statusCode' => 401, + ], + Exception::USER_PASSWORD_RESET_REQUIRED => [ + 'name' => Exception::USER_PASSWORD_RESET_REQUIRED, + 'description' => 'The current user requires a password reset.', + 'statusCode' => 412, + ], + Exception::USER_IP_NOT_WHITELISTED => [ + 'name' => Exception::USER_IP_NOT_WHITELISTED, + 'description' => 'The user\'s IP address is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_IPS environment variable of your Appwrite server.', + 'statusCode' => 401, + ], + Exception::USER_INVALID_CREDENTIALS => [ + 'name' => Exception::USER_INVALID_CREDENTIALS, + 'description' => 'Invalid credentials. Please check the email and password.', + 'statusCode' => 401, + ], + Exception::USER_ALREADY_EXISTS => [ + 'name' => Exception::USER_ALREADY_EXISTS, 'description' => 'A user with the same email ID already exists in your project.', 'statusCode' => 409, ], - Exception::TYPE_USER_BLOCKED => [ - 'name' => Exception::TYPE_USER_BLOCKED, + Exception::USER_BLOCKED => [ + 'name' => Exception::USER_BLOCKED, 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', 'statusCode' => 401, ], - Exception::TYPE_USER_CREATION_FAILED => [ - 'name' => Exception::TYPE_USER_CREATION_FAILED, + Exception::USER_CREATION_FAILED => [ + 'name' => Exception::USER_CREATION_FAILED, 'description' => 'There was an internal server error while creating the user.', 'statusCode' => 500, ], - Exception::TYPE_USER_NOT_FOUND => [ - 'name' => Exception::TYPE_USER_NOT_FOUND, + Exception::USER_NOT_FOUND => [ + 'name' => Exception::USER_NOT_FOUND, 'description' => 'User with the requested ID could not be found.', 'statusCode' => 404, ], - Exception::TYPE_EMAIL_ALREADY_EXISTS => [ - 'name' => Exception::TYPE_EMAIL_ALREADY_EXISTS, + Exception::USER_EMAIL_ALREADY_EXISTS => [ + 'name' => Exception::USER_EMAIL_ALREADY_EXISTS, 'description' => 'Another user with the same email already exists in the current project.', 'statusCode' => 409, ], - Exception::TYPE_PASSWORD_MISMATCH => [ - 'name' => Exception::TYPE_PASSWORD_MISMATCH, + Exception::USER_PASSWORD_MISMATCH => [ + 'name' => Exception::USER_PASSWORD_MISMATCH, 'description' => 'Passwords do not match. Please recheck.', 'statusCode' => 400, ], - Exception::TYPE_AUTH_METHOD_UNSUPPORTED => [ - 'name' => Exception::TYPE_AUTH_METHOD_UNSUPPORTED, + Exception::USER_AUTH_METHOD_UNSUPPORTED => [ + 'name' => Exception::USER_AUTH_METHOD_UNSUPPORTED, 'description' => 'The requested authentication method is either disabled or unsupported.', 'statusCode' => 501, ], - Exception::TYPE_PROVIDER_DISABLED => [ - 'name' => Exception::TYPE_PROVIDER_DISABLED, + + /** OAuth Errors */ + Exception::OAUTH_PROVIDER_DISABLED => [ + 'name' => Exception::OAUTH_PROVIDER_DISABLED, 'description' => 'The chosen OAuth provider is disabled. Please contact your project administrator for more information.', 'statusCode' => 412, ], - Exception::TYPE_PROVIDER_UNSUPPORTED => [ - 'name' => Exception::TYPE_PROVIDER_UNSUPPORTED, + Exception::OAUTH_PROVIDER_UNSUPPORTED => [ + 'name' => Exception::OAUTH_PROVIDER_UNSUPPORTED, 'description' => 'The chosen OAuth provider is unsupported.', 'statusCode' => 501, ], - Exception::TYPE_INVALID_LOGIN_STATE_PARAMS => [ - 'name' => Exception::TYPE_INVALID_LOGIN_STATE_PARAMS, + Exception::OAUTH_INVALID_LOGIN_STATE_PARAMS => [ + 'name' => Exception::OAUTH_INVALID_LOGIN_STATE_PARAMS, 'description' => 'Failed to parse the login state params from the OAuth provider.', 'statusCode' => 500, ], - Exception::TYPE_INVALID_SUCCESS_URL => [ - 'name' => Exception::TYPE_INVALID_SUCCESS_URL, + Exception::OAUTH_INVALID_SUCCESS_URL => [ + 'name' => Exception::OAUTH_INVALID_SUCCESS_URL, 'description' => 'Invalid URL received for OAuth success redirect.', 'statusCode' => 400, ], - Exception::TYPE_INVALID_FAILURE_URL => [ - 'name' => Exception::TYPE_INVALID_FAILURE_URL, + Exception::OAUTH_INVALID_FAILURE_URL => [ + 'name' => Exception::OAUTH_INVALID_FAILURE_URL, 'description' => 'Invalid URL received for OAuth failure redirect.', 'statusCode' => 400, ], - Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED => [ - 'name' => Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED, + Exception::OAUTH_ACCESS_TOKEN_FAILED => [ + 'name' => Exception::OAUTH_ACCESS_TOKEN_FAILED, 'description' => 'Failed to obtain access token from the OAuth provider.', 'statusCode' => 500, ], - Exception::TYPE_MISSING_USER_ID => [ - 'name' => Exception::TYPE_MISSING_USER_ID, + Exception::OAUTH_MISSING_USER_ID => [ + 'name' => Exception::OAUTH_MISSING_USER_ID, 'description' => 'Failed to obtain user id from the OAuth provider.', 'statusCode' => 400, ] diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index ac030f7e7d..3c89e46145 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -4,7 +4,7 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; use Appwrite\Utopia\Response; use Utopia\App; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Validator\Assoc; use Utopia\Validator\WhiteList; use Appwrite\Network\Validator\Email; @@ -70,7 +70,7 @@ App::post('/v1/users') 'deleted' => false ])); } catch (Duplicate $th) { - throw new Exception('Account already exists', 409); + throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS); } $usage @@ -110,7 +110,7 @@ App::get('/v1/users') $cursorUser = $dbForProject->getDocument('users', $cursor); if ($cursorUser->isEmpty()) { - throw new Exception("User '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("User '{$cursor}' for the 'cursor' value not found.", 404, Exception::USER_NOT_FOUND); } } @@ -155,7 +155,7 @@ App::get('/v1/users/:userId') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $usage @@ -187,7 +187,7 @@ App::get('/v1/users/:userId/prefs') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $prefs = $user->getAttribute('prefs', new \stdClass()); @@ -223,7 +223,7 @@ App::get('/v1/users/:userId/sessions') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $sessions = $user->getAttribute('sessions', []); @@ -277,7 +277,7 @@ App::get('/v1/users/:userId/logs') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $audit = new Audit($dbForProject); @@ -377,7 +377,7 @@ App::patch('/v1/users/:userId/status') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', (bool) $status)); @@ -413,7 +413,7 @@ App::patch('/v1/users/:userId/verification') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification)); @@ -449,7 +449,7 @@ App::patch('/v1/users/:userId/name') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('name', $name)); @@ -488,7 +488,7 @@ App::patch('/v1/users/:userId/password') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $user @@ -531,7 +531,7 @@ App::patch('/v1/users/:userId/email') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password')); // Check if request is from an anonymous account for converting @@ -544,7 +544,7 @@ App::patch('/v1/users/:userId/email') try { $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('email', $email)); } catch(Duplicate $th) { - throw new Exception('Email already exists', 409); + throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS); } $audits @@ -581,7 +581,7 @@ App::patch('/v1/users/:userId/prefs') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); @@ -618,7 +618,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $sessions = $user->getAttribute('sessions', []); @@ -673,7 +673,7 @@ App::delete('/v1/users/:userId/sessions') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $sessions = $user->getAttribute('sessions', []); @@ -722,7 +722,7 @@ App::delete('/v1/users/:userId') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } /** diff --git a/app/controllers/general.php b/app/controllers/general.php index 7f82c36a30..dba5caed94 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -8,7 +8,7 @@ use Utopia\Logger\Log\User; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\View; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Config\Config; use Utopia\Domains\Domain; use Appwrite\Auth\Auth; @@ -108,11 +108,11 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons } if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) { - throw new Exception('Missing or unknown project ID', 400); + throw new Exception('Missing or unknown project ID', 400, Exception::PROJECT_UNKNOWN); } $referrer = $request->getReferer(); @@ -214,7 +214,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons && \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE]) && $route->getLabel('origin', false) !== '*' && empty($request->getHeader('x-appwrite-key', ''))) { - throw new Exception($originValidator->getDescription(), 403); + throw new Exception($originValidator->getDescription(), 403, Exception::UNKNOWN_ORIGIN); } /* @@ -283,24 +283,24 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons if(array_key_exists($service, $project->getAttribute('services',[])) && !$project->getAttribute('services',[])[$service] && !Auth::isPrivilegedUser(Authorization::getRoles())) { - throw new Exception('Service is disabled', 503); + throw new Exception('Service is disabled', 503, Exception::SERVICE_DISABLED); } } if (!\in_array($scope, $scopes)) { if ($project->isEmpty()) { // Check if permission is denied because project is missing - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } - throw new Exception($user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')', 401); + throw new Exception($user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')', 401, Exception::UNAUTHORIZED_SCOPE); } if (false === $user->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401); + throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED); } if ($user->getAttribute('reset')) { - throw new Exception('Password reset is required', 412); + throw new Exception('Password reset is required', 412, Exception::USER_PASSWORD_RESET_REQUIRED); } }, ['utopia', 'request', 'response', 'console', 'project', 'dbForConsole', 'user', 'locale', 'clients']); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 47b1b9a4d0..f2abfc90f3 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -4,7 +4,7 @@ use Appwrite\Auth\Auth; use Appwrite\Database\Validator\Authorization; use Appwrite\Messaging\Adapter\Realtime; use Utopia\App; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; use Utopia\Database\Document; @@ -32,7 +32,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud $route = $utopia->match($request); if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope - throw new Exception('Missing or unknown project ID', 400); + throw new Exception('Missing or unknown project ID', 400, Exception::PROJECT_UNKNOWN); } /* @@ -81,7 +81,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not disabled && (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key { - throw new Exception('Too many requests', 429); + throw new Exception('Too many requests', 429, Exception::RATE_LIMIT_EXCEEDED); } } @@ -150,36 +150,36 @@ App::init(function ($utopia, $request, $project) { switch ($route->getLabel('auth.type', '')) { case 'emailPassword': if(($auths['emailPassword'] ?? true) === false) { - throw new Exception('Email / Password authentication is disabled for this project', 501); + throw new Exception('Email / Password authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED); } break; case 'magic-url': if($project->getAttribute('usersAuthMagicURL', true) === false) { - throw new Exception('Magic URL authentication is disabled for this project', 501); + throw new Exception('Magic URL authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED); } break; case 'anonymous': if(($auths['anonymous'] ?? true) === false) { - throw new Exception('Anonymous authentication is disabled for this project', 501); + throw new Exception('Anonymous authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED); } break; case 'invites': if(($auths['invites'] ?? true) === false) { - throw new Exception('Invites authentication is disabled for this project', 501); + throw new Exception('Invites authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED); } break; case 'jwt': if(($auths['JWT'] ?? true) === false) { - throw new Exception('JWT authentication is disabled for this project', 501); + throw new Exception('JWT authentication is disabled for this project', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED); } break; default: - throw new Exception('Unsupported authentication route'); + throw new Exception('Unsupported authentication route', Exception::USER_AUTH_METHOD_UNSUPPORTED); break; } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index f96621049c..2d39bdf288 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -8,42 +8,10 @@ class Exception extends \Exception { /** * Error Codes - */ - const TYPE_NONE = ''; - - /** API */ - const TYPE_PROJECT_NOT_FOUND = 'project_not_found'; - const TYPE_PROJECT_UNKNOWN = 'project_unknown'; - const TYPE_INVALID_ORIGIN = 'invalid_origin'; - const TYPE_SERVICE_DISABLED = 'service_disabled'; - const TYPE_UNAUTHORIZED_SCOPE = 'unauthorized_scope'; - const TYPE_PASSWORD_RESET_REQUIRED = 'password_reset_required'; - const TYPE_STORAGE_ERROR = 'storage_error'; - const TYPE_RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; - const TYPE_SMTP_DISABLED = 'smtp_disabled'; - - /** Users **/ - const TYPE_EMAIL_NOT_WHITELISTED = 'email_not_whitelisted'; - const TYPE_IP_NOT_WHITELISTED = 'ip_not_whitelisted'; - const TYPE_INVALID_TOKEN = 'invalid_token'; - const TYPE_JWT_VERIFICATION_FAILED = 'jwt_verification_failed'; - const TYPE_ANONYMOUS_CONSOLE_USER = 'anonymous_console_user'; - const TYPE_SESSION_NOT_FOUND = 'session_not_found'; - const TYPE_SESSION_ALREADY_EXISTS = 'session_already_exists'; - - /** OAuth **/ - const TYPE_PROVIDER_DISABLED = 'provider_disabled'; - const TYPE_PROVIDER_UNSUPPORTED = 'provider_unsupported'; - const TYPE_INVALID_LOGIN_STATE_PARAMS = 'invalid_login_state_params'; - const TYPE_INVALID_SUCCESS_URL = 'invalid_success_url'; - const TYPE_INVALID_FAILURE_URL = 'invalid_failure_url'; - const TYPE_OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; - const TYPE_MISSING_USER_ID = 'missing_user_id'; - - - /** + * * Naming the error types based on the following convention * _ + * * Appwrite has the follwing entities: * - Users * - Projects @@ -66,10 +34,36 @@ class Exception extends \Exception const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; + const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; + const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; + const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; + + /** OAuth **/ + const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; + const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; + const OAUTH_INVALID_LOGIN_STATE_PARAMS = 'oauth_invalid_login_state_params'; + const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; + const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; + const OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; + const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; + + /** Projects */ + const PROJECT_NOT_FOUND = 'project_not_found'; + const PROJECT_UNKNOWN = 'project_unknown'; + + /** API */ + const UNKNOWN = 'unknown'; + const UNKNOWN_ORIGIN = 'unknown_origin'; + const SERVICE_DISABLED = 'service_disabled'; + const UNAUTHORIZED_SCOPE = 'unauthorized_scope'; + const STORAGE_ERROR = 'storage_error'; + const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; + const SMTP_DISABLED = 'smtp_disabled'; + private $errorCode = ''; - public function __construct(string $message, int $code = 0, string $errorCode = Exception::TYPE_NONE, \Throwable $previous = null) + public function __construct(string $message, int $code = 0, string $errorCode = Exception::UNKNOWN, \Throwable $previous = null) { $this->errorCode = $errorCode; From a932920fb4877b98173a77942528ba9c72794384 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:56:08 +0400 Subject: [PATCH 16/95] feat: update error codes in the accounts API --- 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 d4b7182be5..e1b77cc640 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -68,11 +68,11 @@ App::post('/v1/account') $whitelistIPs = $project->getAttribute('authWhitelistIPs'); if (!empty($whitelistEmails) && !\in_array($email, $whitelistEmails)) { - throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401, Exception::TYPE_EMAIL_NOT_WHITELISTED); + throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401, Exception::USER_EMAIL_NOT_WHITELISTED); } if (!empty($whitelistIPs) && !\in_array($request->getIP(), $whitelistIPs)) { - throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401, Exception::TYPE_IP_NOT_WHITELISTED); + throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401, Exception::USER_IP_NOT_WHITELISTED); } } @@ -84,7 +84,7 @@ App::post('/v1/account') ], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED); } } @@ -110,7 +110,7 @@ App::post('/v1/account') 'deleted' => false ]))); } catch (Duplicate $th) { - throw new Exception('Account already exists', 409, Exception::TYPE_USER_ALREADY_EXISTS); + throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS); } Authorization::unsetRole('role:' . Auth::USER_ROLE_GUEST); @@ -175,11 +175,11 @@ App::post('/v1/account/sessions') ->setParam('resource', 'user/'.($profile ? $profile->getId() : '')) ; - throw new Exception('Invalid credentials', 401, Exception::TYPE_INVALID_CREDENTIALS); // Wrong password or username + throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); // Wrong password or username } if (false === $profile->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401, Exception::TYPE_USER_BLOCKED); // User is in status blocked + throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED); // User is in status blocked } $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -282,7 +282,7 @@ App::get('/v1/account/sessions/oauth2/:provider') } if (empty($appId) || empty($appSecret)) { - throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::TYPE_PROVIDER_DISABLED); + throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::OAUTH_PROVIDER_DISABLED); } $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); From e2333af71631d3a9256f7c6c0b3d68f33153f013 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:57:32 +0400 Subject: [PATCH 17/95] feat: update error codes in the accounts API --- app/controllers/api/account.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e1b77cc640..309ec2dce3 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -288,7 +288,7 @@ App::get('/v1/account/sessions/oauth2/:provider') $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); if (!\class_exists($className)) { - throw new Exception('Provider is not supported', 501, Exception::TYPE_PROVIDER_UNSUPPORTED); + throw new Exception('Provider is not supported', 501, Exception::OAUTH_PROVIDER_UNSUPPORTED); } if(empty($success)) { From 6cdc9388e05007b53b5f4b0db2e2cb7aa1279dea Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:57:51 +0400 Subject: [PATCH 18/95] feat: update error codes in the accounts API --- app/controllers/api/account.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 309ec2dce3..5e6d8656aa 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -406,7 +406,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); if (!\class_exists($className)) { - throw new Exception('Provider is not supported', 501, Exception::TYPE_PROVIDER_UNSUPPORTED); + throw new Exception('Provider is not supported', 501, Exception::OAUTH_PROVIDER_UNSUPPORTED); } $oauth2 = new $className($appId, $appSecret, $callback); @@ -415,7 +415,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') try { $state = \array_merge($defaultState, $oauth2->parseState($state)); } catch (\Exception$exception) { - throw new Exception('Failed to parse login state params as passed from OAuth2 provider', 500, Exception::TYPE_INVALID_LOGIN_STATE_PARAMS); + throw new Exception('Failed to parse login state params as passed from OAuth2 provider', 500, Exception::OAUTH_INVALID_LOGIN_STATE_PARAMS); } } else { $state = $defaultState; From 1b8413fdefd085b294cd6f50a1df3ad5d61178f7 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:58:05 +0400 Subject: [PATCH 19/95] feat: update error codes in the accounts API --- app/controllers/api/account.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 5e6d8656aa..09aaf3a431 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -422,11 +422,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if (!$validateURL->isValid($state['success'])) { - throw new Exception('Invalid redirect URL for success login', 400, Exception::TYPE_INVALID_SUCCESS_URL); + throw new Exception('Invalid redirect URL for success login', 400, Exception::OAUTH_INVALID_SUCCESS_URL); } if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) { - throw new Exception('Invalid redirect URL for failure login', 400, Exception::TYPE_INVALID_FAILURE_URL); + throw new Exception('Invalid redirect URL for failure login', 400, Exception::OAUTH_INVALID_FAILURE_URL); } $state['failure'] = null; From 361cce8ec113cf88c6891af4bb50bc37bb75006e Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:58:26 +0400 Subject: [PATCH 20/95] feat: update error codes in the accounts API --- app/controllers/api/account.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 09aaf3a431..a62e1c8710 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -437,7 +437,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response->redirect($state['failure'], 301, 0); } - throw new Exception('Failed to obtain access token', 500, Exception::TYPE_OAUTH_ACCESS_TOKEN_FAILED); + throw new Exception('Failed to obtain access token', 500, Exception::OAUTH_ACCESS_TOKEN_FAILED); } $oauth2ID = $oauth2->getUserID($accessToken); @@ -447,7 +447,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response->redirect($state['failure'], 301, 0); } - throw new Exception('Missing ID from OAuth2 provider', 400, Exception::TYPE_MISSING_USER_ID); + throw new Exception('Missing ID from OAuth2 provider', 400, Exception::OAUTH_MISSING_USER_ID); } $sessions = $user->getAttribute('sessions', []); @@ -482,7 +482,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $sum = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED); } } From 7f29a9e8c94e83ff7acad667f72768a2d4bbff82 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 16:58:50 +0400 Subject: [PATCH 21/95] feat: update error codes in the accounts API --- 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 a62e1c8710..50a28de355 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -508,13 +508,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'deleted' => false ]))); } catch (Duplicate $th) { - throw new Exception('Account already exists', 409, Exception::TYPE_USER_ALREADY_EXISTS); + throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS); } } } if (false === $user->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401, Exception::TYPE_USER_BLOCKED); // User is in status blocked + throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED); // User is in status blocked } // Create session token, verify user account and update OAuth2 ID and Access Token @@ -637,7 +637,7 @@ App::post('/v1/account/sessions/magic-url') /** @var Appwrite\Event\Event $mails */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::TYPE_SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -655,7 +655,7 @@ App::post('/v1/account/sessions/magic-url') ], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED); } } From d3efbc1ef5cfbe415c8a3c514849bc59c77aef81 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 17:40:31 +0400 Subject: [PATCH 22/95] feat: update error codes in the accounts API --- app/config/errors.php | 5 +++++ app/controllers/api/account.php | 10 +++++----- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index b85841aa6e..1986a6fc5b 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -82,6 +82,11 @@ return [ 'description' => 'A user with the same email ID already exists in your project.', 'statusCode' => 409, ], + Exception::USER_INVALID_TOKEN => [ + 'name' => Exception::USER_INVALID_TOKEN, + 'description' => 'Invalid token.', + 'statusCode' => 401, + ], Exception::USER_BLOCKED => [ 'name' => Exception::USER_BLOCKED, 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 50a28de355..441b2d75cc 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -705,7 +705,7 @@ App::post('/v1/account/sessions/magic-url') $user = $dbForProject->updateDocument('users', $user->getId(), $user); if (false === $user) { - throw new Exception('Failed to save user to DB', 500, Exception::TYPE_USER_CREATION_FAILED); + throw new Exception('Failed to save user to DB', 500, Exception::USER_CREATION_FAILED); } if(empty($url)) { @@ -783,13 +783,13 @@ App::put('/v1/account/sessions/magic-url') $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty() || $user->getAttribute('deleted')) { - throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $token = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_MAGIC_URL, $secret); if (!$token) { - throw new Exception('Invalid login token', 401, Exception::TYPE_INVALID_TOKEN); + throw new Exception('Invalid login token', 401, Exception::USER_INVALID_TOKEN); } $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -839,7 +839,7 @@ App::put('/v1/account/sessions/magic-url') $user = $dbForProject->updateDocument('users', $user->getId(), $user); if (false === $user) { - throw new Exception('Failed saving user to DB', 500, Exception::TYPE_USER_CREATION_FAILED); + throw new Exception('Failed saving user to DB', 500, Exception::USER_CREATION_FAILED); } $audits @@ -912,7 +912,7 @@ App::post('/v1/account/sessions/anonymous') $protocol = $request->getProtocol(); if ('console' === $project->getId()) { - throw new Exception('Failed to create anonymous user.', 401, Exception::TYPE_ANONYMOUS_CONSOLE_USER); + throw new Exception('Failed to create anonymous user.', 401); } if (!$user->isEmpty()) { diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 2d39bdf288..ce2665fec8 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -29,6 +29,7 @@ class Exception extends \Exception const USER_ALREADY_EXISTS = 'user_already_exists'; const USER_BLOCKED = 'user_blocked'; const USER_CREATION_FAILED = 'user_creation_failed'; + const USER_INVALID_TOKEN = 'user_invalid_token'; const USER_NOT_FOUND = 'user_not_found'; const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; From 696709c46c302e1e607517c8c7641b3b9ac77d2c Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 17:54:40 +0400 Subject: [PATCH 23/95] feat: update error codes in the accounts API --- app/config/errors.php | 10 ++++++++++ app/controllers/api/account.php | 4 ++-- src/Appwrite/Extend/Exception.php | 28 +++++++++++++++------------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 1986a6fc5b..961231475a 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -92,6 +92,16 @@ return [ 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', 'statusCode' => 401, ], + Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED => [ + 'name' => Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, + 'description' => 'Anonymous users cannot be created for console project.', + 'statusCode' => 401, + ], + Exception::USER_SESSION_ALREADY_EXISTS => [ + 'name' => Exception::USER_SESSION_ALREADY_EXISTS, + 'description' => 'Cannot create anonymous user when a session is active.', + 'statusCode' => 401, + ], Exception::USER_CREATION_FAILED => [ 'name' => Exception::USER_CREATION_FAILED, 'description' => 'There was an internal server error while creating the user.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 441b2d75cc..1e6ae7c59f 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -912,11 +912,11 @@ App::post('/v1/account/sessions/anonymous') $protocol = $request->getProtocol(); if ('console' === $project->getId()) { - throw new Exception('Failed to create anonymous user.', 401); + throw new Exception('Failed to create anonymous user.', 401, Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED); } if (!$user->isEmpty()) { - throw new Exception('Cannot create an anonymous user when logged in.', 401, Exception::TYPE_SESSION_ALREADY_EXISTS); + throw new Exception('Cannot create an anonymous user when logged in.', 401, Exception::USER_SESSION_ALREADY_EXISTS); } $limit = $project->getAttribute('auths', [])['limit'] ?? 0; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index ce2665fec8..76e44cc13f 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -25,19 +25,21 @@ class Exception extends \Exception */ /** Users */ - const USER_COUNT_EXCEEDED = 'user_count_exceeded'; - const USER_ALREADY_EXISTS = 'user_already_exists'; - const USER_BLOCKED = 'user_blocked'; - const USER_CREATION_FAILED = 'user_creation_failed'; - const USER_INVALID_TOKEN = 'user_invalid_token'; - const USER_NOT_FOUND = 'user_not_found'; - const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; - const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; - const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; - const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; - const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; - const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; - const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; + const USER_COUNT_EXCEEDED = 'user_count_exceeded'; + const USER_ALREADY_EXISTS = 'user_already_exists'; + const USER_BLOCKED = 'user_blocked'; + const USER_CREATION_FAILED = 'user_creation_failed'; + const USER_INVALID_TOKEN = 'user_invalid_token'; + const USER_NOT_FOUND = 'user_not_found'; + const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; + const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; + const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; + const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; + const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; + const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; + const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; + const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; + const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; /** OAuth **/ const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; From d9714e8a5eade64ec1705b2acf766399978a37f7 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 17:59:45 +0400 Subject: [PATCH 24/95] feat: update error codes in the accounts API --- app/config/errors.php | 5 +++++ app/controllers/api/account.php | 22 +++++++++++----------- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 961231475a..7d4b22ba2d 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -122,6 +122,11 @@ return [ 'description' => 'Passwords do not match. Please recheck.', 'statusCode' => 400, ], + Exception::USER_SESSION_NOT_FOUND => [ + 'name' => Exception::USER_SESSION_NOT_FOUND, + 'description' => 'The current user session could not be found.', + 'statusCode' => 404, + ], Exception::USER_AUTH_METHOD_UNSUPPORTED => [ 'name' => Exception::USER_AUTH_METHOD_UNSUPPORTED, 'description' => 'The requested authentication method is either disabled or unsupported.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 1e6ae7c59f..bf85e0463d 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -927,7 +927,7 @@ App::post('/v1/account/sessions/anonymous') ], APP_LIMIT_USERS); if ($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::TYPE_USER_LIMIT_EXCEEDED); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED); } } @@ -1051,7 +1051,7 @@ App::post('/v1/account/jwt') } if ($current->isEmpty()) { - throw new Exception('No valid session found', 401, Exception::TYPE_SESSION_NOT_FOUND); + throw new Exception('No valid session found', 404, Exception::USER_SESSION_NOT_FOUND); } $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. @@ -1296,7 +1296,7 @@ App::get('/v1/account/sessions/:sessionId') } } - throw new Exception('Session not found', 404, Exception::TYPE_SESSION_NOT_FOUND); + throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND); }); App::patch('/v1/account/name') @@ -1370,7 +1370,7 @@ App::patch('/v1/account/password') // Check old password only if its an existing user. if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password - throw new Exception('Invalid credentials', 401, Exception::TYPE_INVALID_CREDENTIALS); + throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); } $user = $dbForProject->updateDocument('users', $user->getId(), $user @@ -1422,14 +1422,14 @@ App::patch('/v1/account/email') !$isAnonymousUser && !Auth::passwordVerify($password, $user->getAttribute('password')) ) { // Double check user password - throw new Exception('Invalid credentials', 401, Exception::TYPE_INVALID_CREDENTIALS); + throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); } $email = \strtolower($email); $profile = $dbForProject->findOne('users', [new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address if ($profile) { - throw new Exception('User already registered', 409, Exception::TYPE_USER_ALREADY_EXISTS); + throw new Exception('User already registered', 409, Exception::USER_ALREADY_EXISTS); } try { @@ -1440,7 +1440,7 @@ App::patch('/v1/account/email') ->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')])) ); } catch(Duplicate $th) { - throw new Exception('Email already exists', 409, Exception::TYPE_EMAIL_ALREADY_EXISTS); + throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS); } $audits @@ -1644,7 +1644,7 @@ App::delete('/v1/account/sessions/:sessionId') } } - throw new Exception('Session not found', 404, Exception::TYPE_SESSION_NOT_FOUND); + throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND); }); App::delete('/v1/account/sessions') @@ -1764,7 +1764,7 @@ App::post('/v1/account/recovery') /** @var Appwrite\Stats\Stats $usage */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::TYPE_SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -1775,11 +1775,11 @@ App::post('/v1/account/recovery') $profile = $dbForProject->findOne('users', [new Query('deleted', Query::TYPE_EQUAL, [false]), new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address if (!$profile) { - throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } if (false === $profile->getAttribute('status')) { // Account is blocked - throw new Exception('Invalid credentials. User is blocked', 401, Exception::TYPE_USER_BLOCKED); + throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED); } $expire = \time() + Auth::TOKEN_EXPIRATION_RECOVERY; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 76e44cc13f..ffb24886db 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -39,6 +39,7 @@ class Exception extends \Exception const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; + const USER_SESSION_NOT_FOUND = 'user_session_not_found'; const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; /** OAuth **/ From 593ef1545009155cb634a2c2184ede32f3d850f2 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:02:14 +0400 Subject: [PATCH 25/95] feat: update error codes in the accounts API --- app/controllers/api/account.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index bf85e0463d..841d6153dd 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1870,20 +1870,20 @@ App::put('/v1/account/recovery') /** @var Appwrite\Stats\Stats $usage */ if ($password !== $passwordAgain) { - throw new Exception('Passwords must match', 400, Exception::TYPE_PASSWORD_MISMATCH); + throw new Exception('Passwords must match', 400, Exception::USER_PASSWORD_MISMATCH); } $profile = $dbForProject->getDocument('users', $userId); if ($profile->isEmpty() || $profile->getAttribute('deleted')) { - throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $tokens = $profile->getAttribute('tokens', []); $recovery = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_RECOVERY, $secret); if (!$recovery) { - throw new Exception('Invalid recovery token', 401, Exception::TYPE_INVALID_TOKEN); + throw new Exception('Invalid recovery token', 401, Exception::USER_INVALID_TOKEN); } Authorization::setRole('user:' . $profile->getId()); @@ -1957,7 +1957,7 @@ App::post('/v1/account/verification') /** @var Appwrite\Stats\Stats $usage */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::TYPE_SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -2055,14 +2055,14 @@ App::put('/v1/account/verification') $profile = $dbForProject->getDocument('users', $userId); if ($profile->isEmpty()) { - throw new Exception('User not found', 404, Exception::TYPE_USER_NOT_FOUND); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $tokens = $profile->getAttribute('tokens', []); $verification = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_VERIFICATION, $secret); if (!$verification) { - throw new Exception('Invalid verification token', 401, Exception::TYPE_INVALID_TOKEN); + throw new Exception('Invalid verification token', 401, Exception::USER_INVALID_TOKEN); } Authorization::setRole('user:' . $profile->getId()); From bc3454928b645b659ca91971e8dc742767e6c52c Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:10:12 +0400 Subject: [PATCH 26/95] feat: update error codes in the avatars API --- app/config/errors.php | 7 ++++++- app/controllers/api/avatars.php | 10 +++++----- src/Appwrite/Extend/Exception.php | 9 +++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 7d4b22ba2d..7fe1343b6c 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -168,5 +168,10 @@ return [ 'name' => Exception::OAUTH_MISSING_USER_ID, 'description' => 'Failed to obtain user id from the OAuth provider.', 'statusCode' => 400, - ] + ], + + /** Avatars */ + + + /** Files */ ]; \ No newline at end of file diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 161e87b130..0d79bb92b4 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -8,7 +8,7 @@ use Utopia\App; use Utopia\Cache\Adapter\Filesystem; use Utopia\Cache\Cache; use Utopia\Config\Config; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Image\Image; use Utopia\Validator\Boolean; use Utopia\Validator\HexColor; @@ -25,15 +25,15 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response) $set = Config::getParam('avatar-' . $type, []); if (empty($set)) { - throw new Exception('Avatar set not found', 404); + throw new Exception('Avatar set not found', 404, Exception::AVATAR_SET_NOT_FOUND); } if (!\array_key_exists($code, $set)) { - throw new Exception('Avatar not found', 404); + throw new Exception('Avatar not found', 404, Exception::AVATAR_NOT_FOUND); } if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500); + throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); } $output = 'png'; @@ -43,7 +43,7 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response) $type = 'png'; if (!\is_readable($path)) { - throw new Exception('File not readable in ' . $path, 500); + throw new Exception('File not readable in ' . $path, 500, Exception::FILE_NOT_READABLE); } $cache = new Cache(new Filesystem(APP_STORAGE_CACHE . '/app-0')); // Limit file number or size diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index ffb24886db..e5ca2bd45f 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -51,6 +51,15 @@ class Exception extends \Exception const OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; + /** Avatars */ + const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; + const AVATAR_NOT_FOUND = 'avatar_not_found'; + const IMAGIC_EXTENSION_MISSING = 'imagic_extension_missing'; + + /** Files */ + const FILE_NOT_FOUND = 'file_not_found'; + const FILE_NOT_READABLE = 'file_not_readable'; + /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; const PROJECT_UNKNOWN = 'project_unknown'; From 66a4c2b8776b3d837c4d31f101fe5b2726928d3c Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:13:16 +0400 Subject: [PATCH 27/95] feat: update error codes in the accounts API --- app/config/errors.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index 7fe1343b6c..37dbc84271 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -171,7 +171,32 @@ return [ ], /** Avatars */ + Exception::AVATAR_SET_NOT_FOUND => [ + 'name' => Exception::AVATAR_SET_NOT_FOUND, + 'description' => 'The requested avatar set could not be found.', + 'statusCode' => 404 + ], + Exception::AVATAR_NOT_FOUND => [ + 'name' => Exception::AVATAR_NOT_FOUND, + 'description' => 'The request avatar could not be found.', + 'statusCode' => 404, + ], + Exception::IMAGIC_EXTENSION_MISSING => [ + 'name' => Exception::IMAGIC_EXTENSION_MISSING, + 'description' => 'The Imagic extension could not be found.', + 'statusCode' => 500, + ], /** Files */ + Exception::FILE_NOT_FOUND => [ + 'name' => Exception::FILE_NOT_FOUND, + 'description' => 'The requested file could not be found.', + 'statusCode' => 404, + ], + Exception::FILE_NOT_READABLE => [ + 'name' => Exception::FILE_NOT_READABLE, + 'description' => 'There was an error reading the file from disk.', + 'statusCode' => 500, + ], ]; \ No newline at end of file From fd46cdc41260daeac2bde7180e690196d5453cd3 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:16:14 +0400 Subject: [PATCH 28/95] feat: update error codes in the accounts API --- app/config/errors.php | 5 +++++ app/controllers/api/avatars.php | 4 ++-- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 37dbc84271..bb861506bb 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -186,6 +186,11 @@ return [ 'description' => 'The Imagic extension could not be found.', 'statusCode' => 500, ], + Exception::AVATAR_IMAGE_NOT_FOUND => [ + 'name' => Exception::AVATAR_IMAGE_NOT_FOUND, + 'description' => 'The requested image was not found.', + 'statusCode' => 404, + ], /** Files */ diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 0d79bb92b4..fce98c741d 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -169,13 +169,13 @@ App::get('/v1/avatars/image') } if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500); + throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); } $fetch = @\file_get_contents($url, false); if (!$fetch) { - throw new Exception('Image not found', 404); + throw new Exception('Image not found', 404, Exception::AVATAR_IMAGE_NOT_FOUND); } try { diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index e5ca2bd45f..a0902f68a9 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -55,6 +55,7 @@ class Exception extends \Exception const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; const AVATAR_NOT_FOUND = 'avatar_not_found'; const IMAGIC_EXTENSION_MISSING = 'imagic_extension_missing'; + const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; /** Files */ const FILE_NOT_FOUND = 'file_not_found'; From c7e1050ce572cfa05461eac621d3aae10b085eef Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:17:26 +0400 Subject: [PATCH 29/95] feat: update error codes in the avatars API --- app/config/errors.php | 5 +++++ app/controllers/api/avatars.php | 2 +- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index bb861506bb..c19255776a 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -191,6 +191,11 @@ return [ 'description' => 'The requested image was not found.', 'statusCode' => 404, ], + Exception::AVATAR_CANNOT_PARSE_IMAGE => [ + 'name' => Exception::AVATAR_CANNOT_PARSE_IMAGE, + 'description' => 'The requested image could not be parsed.', + 'statusCode' => 500, + ], /** Files */ diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index fce98c741d..7401799425 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -181,7 +181,7 @@ App::get('/v1/avatars/image') try { $image = new Image($fetch); } catch (\Exception$exception) { - throw new Exception('Unable to parse image', 500); + throw new Exception('Unable to parse image', 500, Exception::AVATAR_CANNOT_PARSE_IMAGE); } $image->crop((int) $width, (int) $height); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index a0902f68a9..0c4a3b6d8c 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -56,6 +56,7 @@ class Exception extends \Exception const AVATAR_NOT_FOUND = 'avatar_not_found'; const IMAGIC_EXTENSION_MISSING = 'imagic_extension_missing'; const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; + const AVATAR_CANNOT_PARSE_IMAGE = 'avatar_cannot_parse_image'; /** Files */ const FILE_NOT_FOUND = 'file_not_found'; From 534d541b1fef1e95227c3891221dadce82aeb48f Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:17:52 +0400 Subject: [PATCH 30/95] feat: update error codes in the avatars API --- app/controllers/api/avatars.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 7401799425..7165e67c43 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -238,7 +238,7 @@ App::get('/v1/avatars/favicon') } if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500); + throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); } $curl = \curl_init(); From f6599f545ed7f419f32ccb186cc78bf1ab243635 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:19:10 +0400 Subject: [PATCH 31/95] feat: update error codes in the avatars API --- app/config/errors.php | 5 +++++ app/controllers/api/avatars.php | 2 +- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index c19255776a..13264fbf5c 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -196,6 +196,11 @@ return [ 'description' => 'The requested image could not be parsed.', 'statusCode' => 500, ], + Exception::AVATAR_REMOTE_URL_FAILED => [ + 'name' => Exception::AVATAR_REMOTE_URL_FAILED, + 'description' => 'The remote URL could not be fetched.', + 'statusCode' => 404, + ], /** Files */ diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 7165e67c43..7b9c770ebb 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -259,7 +259,7 @@ App::get('/v1/avatars/favicon') \curl_close($curl); if (!$html) { - throw new Exception('Failed to fetch remote URL', 404); + throw new Exception('Failed to fetch remote URL', 404, Exception::AVATAR_REMOTE_URL_FAILED); } $doc = new DOMDocument(); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 0c4a3b6d8c..070e4f32ce 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -57,6 +57,7 @@ class Exception extends \Exception const IMAGIC_EXTENSION_MISSING = 'imagic_extension_missing'; const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; const AVATAR_CANNOT_PARSE_IMAGE = 'avatar_cannot_parse_image'; + const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; /** Files */ const FILE_NOT_FOUND = 'file_not_found'; From 42fcb291d455ca1266efb5b17a9a486b1312d5bb Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:21:03 +0400 Subject: [PATCH 32/95] feat: update error codes in the avatars API --- app/config/errors.php | 5 +++++ app/controllers/api/avatars.php | 4 ++-- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 13264fbf5c..4279b0ce2d 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -201,6 +201,11 @@ return [ 'description' => 'The remote URL could not be fetched.', 'statusCode' => 404, ], + Exception::AVATAR_ICON_NOT_FOUND => [ + 'name' => Exception::AVATAR_ICON_NOT_FOUND, + 'description' => 'The requested favicon could not be found.', + 'statusCode' => 404, + ], /** Files */ diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 7b9c770ebb..c106777a36 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -317,7 +317,7 @@ App::get('/v1/avatars/favicon') $data = @\file_get_contents($outputHref, false); if (empty($data) || (\mb_substr($data, 0, 5) === 'save($key, $data); @@ -333,7 +333,7 @@ App::get('/v1/avatars/favicon') $fetch = @\file_get_contents($outputHref, false); if (!$fetch) { - throw new Exception('Icon not found', 404); + throw new Exception('Icon not found', 404, Exception::AVATAR_ICON_NOT_FOUND); } $image = new Image($fetch); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 070e4f32ce..2c90d16805 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -58,6 +58,7 @@ class Exception extends \Exception const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; const AVATAR_CANNOT_PARSE_IMAGE = 'avatar_cannot_parse_image'; const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; + const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Files */ const FILE_NOT_FOUND = 'file_not_found'; From 2c14abb14351439642de5e0abc506d8f0d69ba6e Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:32:28 +0400 Subject: [PATCH 33/95] feat: update error codes in the storage API --- app/config/errors.php | 25 ++++++++++++++++++++----- app/controllers/api/avatars.php | 2 +- app/controllers/api/storage.php | 10 +++++----- src/Appwrite/Extend/Exception.php | 9 ++++++--- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 4279b0ce2d..4ed928ec4b 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -208,15 +208,30 @@ return [ ], - /** Files */ - Exception::FILE_NOT_FOUND => [ - 'name' => Exception::FILE_NOT_FOUND, + /** Storage */ + Exception::STORAGE_FILE_NOT_FOUND => [ + 'name' => Exception::STORAGE_FILE_NOT_FOUND, 'description' => 'The requested file could not be found.', 'statusCode' => 404, ], - Exception::FILE_NOT_READABLE => [ - 'name' => Exception::FILE_NOT_READABLE, + Exception::STORAGE_FILE_NOT_READABLE => [ + 'name' => Exception::STORAGE_FILE_NOT_READABLE, 'description' => 'There was an error reading the file from disk.', 'statusCode' => 500, ], + Exception::STORAGE_INVALID_READ_PERMISSIONS => [ + 'name' => Exception::STORAGE_INVALID_READ_PERMISSIONS, + 'description' => 'Invalid format for read permissions. Please check the documentation.', + 'statusCode' => 400, + ], + Exception::STORAGE_INVALID_WRITE_PERMISSIONS => [ + 'name' => Exception::STORAGE_INVALID_WRITE_PERMISSIONS, + 'description' => 'Invalid format for write permissions. Please check the documentation.', + 'statusCode' => 400, + ], + Exception::STORAGE_INVALID_FILE_SIZE => [ + 'name' => Exception::STORAGE_INVALID_FILE_SIZE, + 'description' => 'The file size is either not valid or exceeds the maximum allowed size.', + 'statusCode' => 400, + ], ]; \ No newline at end of file diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index c106777a36..c3bd8721ef 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -43,7 +43,7 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response) $type = 'png'; if (!\is_readable($path)) { - throw new Exception('File not readable in ' . $path, 500, Exception::FILE_NOT_READABLE); + throw new Exception('File not readable in ' . $path, 500, Exception::STORAGE_FILE_NOT_READABLE); } $cache = new Cache(new Filesystem(APP_STORAGE_CACHE . '/app-0')); // Limit file number or size diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 1dba0c722a..779f4218ab 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -2,7 +2,7 @@ use Appwrite\Auth\Auth; use Utopia\App; -use Utopia\Exception; +use Appwrite\Extend\Exception use Utopia\Validator\ArrayList; use Utopia\Validator\WhiteList; use Utopia\Validator\Range; @@ -68,12 +68,12 @@ App::post('/v1/storage/files') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_READ_PERMISSIONS); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_WRITE_PERMISSIONS); } } } @@ -102,13 +102,13 @@ App::post('/v1/storage/files') //} if (!$fileSize->isValid($file['size'])) { // Check if file size is exceeding allowed limit - throw new Exception('File size not allowed', 400); + throw new Exception('File size not allowed', 400, Exception::STORAGE_INVALID_FILE_SIZE); } $device = Storage::getDevice('files'); if (!$upload->isValid($file['tmp_name'])) { - throw new Exception('Invalid file', 403); + throw new Exception('Invalid file', 403, ); } // Save to storage diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 2c90d16805..abada2a97a 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -60,9 +60,12 @@ class Exception extends \Exception const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; - /** Files */ - const FILE_NOT_FOUND = 'file_not_found'; - const FILE_NOT_READABLE = 'file_not_readable'; + /** Storage */ + const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; + const STORAGE_FILE_NOT_READABLE = 'storage_file_not_readable'; + const STORAGE_INVALID_READ_PERMISSIONS = 'storage_invalid_read_permissions'; + const STORAGE_INVALID_WRITE_PERMISSIONS = 'storage_invalid_write_permissions'; + const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; From 6a8401dfe56384b792a1e5a528b7adcc7f1118ea Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:35:17 +0400 Subject: [PATCH 34/95] feat: update error codes in the storage API --- app/config/errors.php | 5 +++++ app/controllers/api/storage.php | 2 +- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index 4ed928ec4b..0031130ed4 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -234,4 +234,9 @@ return [ 'description' => 'The file size is either not valid or exceeds the maximum allowed size.', 'statusCode' => 400, ], + Exception::STORAGE_INVALID_FILE => [ + 'name' => Exception::STORAGE_INVALID_FILE, + 'description' => 'The uploaded file is invalid. Please check the file and try again.', + 'statusCode' => 403, + ], ]; \ No newline at end of file diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 779f4218ab..cafad07872 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -108,7 +108,7 @@ App::post('/v1/storage/files') $device = Storage::getDevice('files'); if (!$upload->isValid($file['tmp_name'])) { - throw new Exception('Invalid file', 403, ); + throw new Exception('Invalid file', 403, Exception::STORAGE_INVALID_FILE); } // Save to storage diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index abada2a97a..4fa15eabd1 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -66,6 +66,7 @@ class Exception extends \Exception const STORAGE_INVALID_READ_PERMISSIONS = 'storage_invalid_read_permissions'; const STORAGE_INVALID_WRITE_PERMISSIONS = 'storage_invalid_write_permissions'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; + const STORAGE_INVALID_FILE = 'storage_invalid_file'; /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; From d9fbe80317f67b7b4c1408d957f3e18301ed1083 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:38:59 +0400 Subject: [PATCH 35/95] feat: update error codes in the storage API --- app/config/errors.php | 5 +++++ app/controllers/api/storage.php | 4 ++-- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 0031130ed4..bfe1c2ec65 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -239,4 +239,9 @@ return [ 'description' => 'The uploaded file is invalid. Please check the file and try again.', 'statusCode' => 403, ], + Exception::STORAGE_FAILED_TO_MOVE_FILE => [ + 'name' => Exception::STORAGE_FAILED_TO_MOVE_FILE, + 'description' => 'Failed to copy the uploaded file.', + 'statusCode' => 500, + ], ]; \ No newline at end of file diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index cafad07872..63d9bf0ee9 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -116,7 +116,7 @@ App::post('/v1/storage/files') $path = $device->getPath(\uniqid().'.'.\pathinfo($file['name'], PATHINFO_EXTENSION)); if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move' - throw new Exception('Failed moving file', 500); + throw new Exception('Failed moving file', 500, Exception::STORAGE_FAILED_TO_MOVE_FILE); } $mimeType = $device->getFileMimeType($path); // Get mime-type before compression and encryption @@ -127,7 +127,7 @@ App::post('/v1/storage/files') if (!$antivirus->fileScan($path)) { $device->delete($path); - throw new Exception('Invalid file', 403); + throw new Exception('Invalid file', 403, Exception::STORAGE_INVALID_FILE); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 4fa15eabd1..819115e789 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -67,6 +67,7 @@ class Exception extends \Exception const STORAGE_INVALID_WRITE_PERMISSIONS = 'storage_invalid_write_permissions'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; const STORAGE_INVALID_FILE = 'storage_invalid_file'; + const STORAGE_FAILED_TO_MOVE_FILE = 'storage_failed_to_move_file'; /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; From 4905792bb566be7ab77b2ac3102ffadb22edc685 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:40:22 +0400 Subject: [PATCH 36/95] feat: update error codes in the storage API --- app/config/errors.php | 7 ++++++- app/controllers/api/storage.php | 2 +- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index bfe1c2ec65..fc5d8ab871 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -241,7 +241,12 @@ return [ ], Exception::STORAGE_FAILED_TO_MOVE_FILE => [ 'name' => Exception::STORAGE_FAILED_TO_MOVE_FILE, - 'description' => 'Failed to copy the uploaded file.', + 'description' => 'Failed to move the uploaded file.', + 'statusCode' => 500, + ], + Exception::STORAGE_FAILED_TO_WRITE_FILE => [ + 'name' => Exception::STORAGE_FAILED_TO_WRITE_FILE, + 'description' => 'Failed to save the uploaded file.', 'statusCode' => 500, ], ]; \ No newline at end of file diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 63d9bf0ee9..b6e014eb71 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -141,7 +141,7 @@ App::post('/v1/storage/files') $data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag); if (!$device->write($path, $data, $mimeType)) { - throw new Exception('Failed to save file', 500); + throw new Exception('Failed to save file', 500, Exception::STORAGE_FAILED_TO_WRITE_FILE); } $sizeActual = $device->getFileSize($path); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 819115e789..2b585d4b57 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -68,6 +68,7 @@ class Exception extends \Exception const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; const STORAGE_INVALID_FILE = 'storage_invalid_file'; const STORAGE_FAILED_TO_MOVE_FILE = 'storage_failed_to_move_file'; + const STORAGE_FAILED_TO_WRITE_FILE = 'storage_failed_to_write_file'; /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; From 9ad151006b64c893e9f8364c793367bbef7bea8e Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:44:48 +0400 Subject: [PATCH 37/95] feat: update error codes in the storage API --- app/config/errors.php | 10 ++++++++++ app/controllers/api/storage.php | 30 +++++++++++++++--------------- src/Appwrite/Extend/Exception.php | 2 ++ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index fc5d8ab871..22d72f8acd 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -214,6 +214,16 @@ return [ 'description' => 'The requested file could not be found.', 'statusCode' => 404, ], + Exception::STORAGE_DEVICE_NOT_FOUND => [ + 'name' => Exception::STORAGE_DEVICE_NOT_FOUND, + 'description' => 'The requested storage device could not be found.', + 'statusCode' => 400, + ], + Exception::STORAGE_FAILED_TO_DELETE_FILE => [ + 'name' => Exception::STORAGE_FAILED_TO_DELETE_FILE, + 'description' => 'There was an issue deleting the file from the database', + 'statusCode' => 500, + ], Exception::STORAGE_FILE_NOT_READABLE => [ 'name' => Exception::STORAGE_FILE_NOT_READABLE, 'description' => 'There was an error reading the file from disk.', diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index b6e014eb71..a74240e716 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -213,7 +213,7 @@ App::get('/v1/storage/files') $cursorFile = $dbForProject->getDocument('files', $cursor); if ($cursorFile->isEmpty()) { - throw new Exception("File '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("File '{$cursor}' for the 'cursor' value not found.", 400, Exception::STORAGE_FILE_NOT_FOUND); } } @@ -257,7 +257,7 @@ App::get('/v1/storage/files/:fileId') $file = $dbForProject->getDocument('files', $fileId); if (empty($file->getId())) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $usage ->setParam('storage.files.read', 1) @@ -304,11 +304,11 @@ App::get('/v1/storage/files/:fileId/preview') $storage = 'files'; if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500); + throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); } if (!Storage::exists($storage)) { - throw new Exception('No such storage device', 400); + throw new Exception('No such storage device', 400, Exception::STORAGE_DEVICE_NOT_FOUND); } if ((\strpos($request->getAccept(), 'image/webp') === false) && ('webp' == $output)) { // Fallback webp to jpeg when no browser support @@ -325,7 +325,7 @@ App::get('/v1/storage/files/:fileId/preview') $file = $dbForProject->getDocument('files', $fileId); if (empty($file->getId())) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $path = $file->getAttribute('path'); @@ -347,7 +347,7 @@ App::get('/v1/storage/files/:fileId/preview') $device = Storage::getDevice('files'); if (!\file_exists($path)) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $cache = new Cache(new Filesystem(APP_STORAGE_CACHE.'/app-'.$project->getId())); // Limit file number or size @@ -450,13 +450,13 @@ App::get('/v1/storage/files/:fileId/download') $file = $dbForProject->getDocument('files', $fileId); if (empty($file->getId())) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $path = $file->getAttribute('path', ''); if (!\file_exists($path)) { - throw new Exception('File not found in '.$path, 404); + throw new Exception('File not found in '.$path, 404, Exception::STORAGE_FILE_NOT_FOUND); } $compressor = new GZIP(); @@ -516,13 +516,13 @@ App::get('/v1/storage/files/:fileId/view') $mimes = Config::getParam('storage-mimes'); if (empty($file->getId())) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $path = $file->getAttribute('path', ''); if (!\file_exists($path)) { - throw new Exception('File not found in '.$path, 404); + throw new Exception('File not found in '.$path, 404, Exception::STORAGE_FILE_NOT_FOUND); } $compressor = new GZIP(); @@ -602,12 +602,12 @@ App::put('/v1/storage/files/:fileId') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_READ_PERMISSIONS); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_WRITE_PERMISSIONS); } } } @@ -615,7 +615,7 @@ App::put('/v1/storage/files/:fileId') $file = $dbForProject->getDocument('files', $fileId); if (empty($file->getId())) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $file = $dbForProject->updateDocument('files', $fileId, new Document(\array_merge($file->getArrayCopy(), [ @@ -664,14 +664,14 @@ App::delete('/v1/storage/files/:fileId') $file = $dbForProject->getDocument('files', $fileId); if (empty($file->getId())) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $device = Storage::getDevice('files'); if ($device->delete($file->getAttribute('path', ''))) { if (!$dbForProject->deleteDocument('files', $fileId)) { - throw new Exception('Failed to remove file from DB', 500); + throw new Exception('Failed to remove file from DB', 500, Exception::STORAGE_FAILED_TO_DELETE_FILE); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 2b585d4b57..381fe04c95 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -62,6 +62,8 @@ class Exception extends \Exception /** Storage */ const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; + const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; + const STORAGE_FAILED_TO_DELETE_FILE = 'storage_failed_to_delete_file'; const STORAGE_FILE_NOT_READABLE = 'storage_file_not_readable'; const STORAGE_INVALID_READ_PERMISSIONS = 'storage_invalid_read_permissions'; const STORAGE_INVALID_WRITE_PERMISSIONS = 'storage_invalid_write_permissions'; From 7085bc81d1e5240b0b45a2254d6ed015fec194f0 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:45:09 +0400 Subject: [PATCH 38/95] feat: update error codes in the storage API --- app/controllers/api/storage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index a74240e716..88d76cb69d 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -2,7 +2,7 @@ use Appwrite\Auth\Auth; use Utopia\App; -use Appwrite\Extend\Exception +use Appwrite\Extend\Exception; use Utopia\Validator\ArrayList; use Utopia\Validator\WhiteList; use Utopia\Validator\Range; From d756a9b97274a28008bcc9aa3c41284890f98a0e Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 18:52:21 +0400 Subject: [PATCH 39/95] feat: update error codes in the teams API --- app/config/errors.php | 16 ++++++++++++- app/controllers/api/teams.php | 40 +++++++++++++++---------------- src/Appwrite/Extend/Exception.php | 6 +++++ 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 22d72f8acd..6c964e3c34 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -170,6 +170,21 @@ return [ 'statusCode' => 400, ], + /** Teams */ + Exception::TEAM_NOT_FOUND => [ + 'name' => Exception::TEAM_NOT_FOUND, + 'description' => 'Team with the requested ID could not be found.', + 'statusCode' => 404, + ], + + + /** Membership */ + Exception::MEMBERSHIP_NOT_FOUND => [ + 'name' => Exception::MEMBERSHIP_NOT_FOUND, + 'description' => 'Membership with the requested ID could not be found.', + 'statusCode' => 404, + ], + /** Avatars */ Exception::AVATAR_SET_NOT_FOUND => [ 'name' => Exception::AVATAR_SET_NOT_FOUND, @@ -207,7 +222,6 @@ return [ 'statusCode' => 404, ], - /** Storage */ Exception::STORAGE_FILE_NOT_FOUND => [ 'name' => Exception::STORAGE_FILE_NOT_FOUND, diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 0a5133d6b9..823b9881ab 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -8,7 +8,7 @@ use Appwrite\Utopia\Response; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Host; use Utopia\App; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Config\Config; use Utopia\Validator\Text; use Utopia\Validator\Range; @@ -117,7 +117,7 @@ App::get('/v1/teams') $cursorTeam = $dbForProject->getDocument('teams', $cursor); if ($cursorTeam->isEmpty()) { - throw new Exception("Team '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Team '{$cursor}' for the 'cursor' value not found.", 400, Exception::TEAM_NOT_FOUND); } } @@ -157,7 +157,7 @@ App::get('/v1/teams/:teamId') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $response->dynamic($team, Response::MODEL_TEAM); @@ -186,7 +186,7 @@ App::put('/v1/teams/:teamId') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $team = $dbForProject->updateDocument('teams', $team->getId(),$team @@ -222,7 +222,7 @@ App::delete('/v1/teams/:teamId') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $memberships = $dbForProject->find('memberships', [ @@ -287,7 +287,7 @@ App::post('/v1/teams/:teamId/memberships') /** @var Appwrite\Event\Event $mails */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503); + throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); } $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -298,7 +298,7 @@ App::post('/v1/teams/:teamId/memberships') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $invitee = $dbForProject->findOne('users', [new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address @@ -311,7 +311,7 @@ App::post('/v1/teams/:teamId/memberships') $sum = $dbForProject->count('users', [], APP_LIMIT_USERS); if($sum >= $limit) { - throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); + throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED); } } @@ -341,7 +341,7 @@ App::post('/v1/teams/:teamId/memberships') 'search' => implode(' ', [$userId, $email, $name]), ]))); } catch (Duplicate $th) { - throw new Exception('Account already exists', 409); + throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS); } } @@ -447,14 +447,14 @@ App::get('/v1/teams/:teamId/memberships') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } if (!empty($cursor)) { $cursorMembership = $dbForProject->getDocument('memberships', $cursor); if ($cursorMembership->isEmpty()) { - throw new Exception("Membership '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Membership '{$cursor}' for the 'cursor' value not found.", 400, Exception::MEMBERSHIP_NOT_FOUND); } } @@ -502,13 +502,13 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $membership = $dbForProject->getDocument('memberships', $membershipId); if($membership->isEmpty() || empty($membership->getAttribute('userId'))) { - throw new Exception('Membership not found', 404); + throw new Exception('Membership not found', 404, Exception::MEMBERSHIP_NOT_FOUND); } $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); @@ -550,17 +550,17 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $membership = $dbForProject->getDocument('memberships', $membershipId); if ($membership->isEmpty()) { - throw new Exception('Membership not found', 404); + throw new Exception('Membership not found', 404, Exception::MEMBERSHIP_NOT_FOUND); } $profile = $dbForProject->getDocument('users', $membership->getAttribute('userId')); if ($profile->isEmpty()) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -621,7 +621,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $membership = $dbForProject->getDocument('memberships', $membershipId); if ($membership->isEmpty()) { - throw new Exception('Membership not found', 404); + throw new Exception('Membership not found', 404, Exception::MEMBERSHIP_NOT_FOUND); } if ($membership->getAttribute('teamId') !== $teamId) { @@ -631,7 +631,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId)); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } if (Auth::hash($secret) !== $membership->getAttribute('secret')) { @@ -759,13 +759,13 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } try { $dbForProject->deleteDocument('memberships', $membership->getId()); } catch (AuthorizationException $exception) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::UNAUTHORIZED_SCOPE); } catch (\Exception $exception) { throw new Exception('Failed to remove membership from DB', 500); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 381fe04c95..d0cf5ec650 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -51,6 +51,12 @@ class Exception extends \Exception const OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; + /** Teams */ + const TEAM_NOT_FOUND = 'team_not_found'; + + /** Membership */ + const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + /** Avatars */ const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; const AVATAR_NOT_FOUND = 'avatar_not_found'; From 5fc751a9dd83e2fd8ce11c76b811471dbead9f41 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 19:17:19 +0400 Subject: [PATCH 40/95] feat: update error codes in the teams API --- app/config/errors.php | 27 ++++++++++++++++++++++++++- app/controllers/api/teams.php | 18 +++++++++--------- src/Appwrite/Extend/Exception.php | 9 +++++++-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 6c964e3c34..5b90bfa170 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -127,6 +127,11 @@ return [ 'description' => 'The current user session could not be found.', 'statusCode' => 404, ], + Exception::USER_UNAUTHORIZED => [ + 'name' => Exception::USER_UNAUTHORIZED, + 'description' => 'The current user is not authorized to perform the requested action.', + 'statusCode' => 401, + ], Exception::USER_AUTH_METHOD_UNSUPPORTED => [ 'name' => Exception::USER_AUTH_METHOD_UNSUPPORTED, 'description' => 'The requested authentication method is either disabled or unsupported.', @@ -176,14 +181,34 @@ return [ 'description' => 'Team with the requested ID could not be found.', 'statusCode' => 404, ], + Exception::TEAM_DELETION_FAILED => [ + 'name' => Exception::TEAM_DELETION_FAILED, + 'description' => 'Failed to delete team from the database.', + 'statusCode' => 500, + ], + Exception::TEAM_INVITATION_ALREADY_EXISTS => [ + 'name' => Exception::TEAM_INVITATION_ALREADY_EXISTS, + 'description' => 'The current user already has an invitation to this team.', + 'statusCode' => 409, + ], + Exception::TEAM_INVITE_NOT_FOUND => [ + 'name' => Exception::TEAM_INVITE_NOT_FOUND, + 'description' => 'The requested invitation could not be found.', + 'statusCode' => 409, + ], + - /** Membership */ Exception::MEMBERSHIP_NOT_FOUND => [ 'name' => Exception::MEMBERSHIP_NOT_FOUND, 'description' => 'Membership with the requested ID could not be found.', 'statusCode' => 404, ], + Exception::MEMBERSHIP_DELETION_FAILED => [ + 'name' => Exception::MEMBERSHIP_DELETION_FAILED, + 'description' => 'Failed to delete membership from the database.', + 'statusCode' => 500, + ], /** Avatars */ Exception::AVATAR_SET_NOT_FOUND => [ diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 823b9881ab..bc38a28bd2 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -232,12 +232,12 @@ App::delete('/v1/teams/:teamId') // TODO delete all members individually from the user object foreach ($memberships as $membership) { if (!$dbForProject->deleteDocument('memberships', $membership->getId())) { - throw new Exception('Failed to remove membership for team from DB', 500); + throw new Exception('Failed to remove membership for team from DB', 500, Exception::MEMBERSHIP_DELETION_FAILED); } } if (!$dbForProject->deleteDocument('teams', $teamId)) { - throw new Exception('Failed to remove team from DB', 500); + throw new Exception('Failed to remove team from DB', 500, Exception::TEAM_DELETION_FAILED); } $deletes @@ -348,7 +348,7 @@ App::post('/v1/teams/:teamId/memberships') $isOwner = Authorization::isRole('team:'.$team->getId().'/owner');; if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) - throw new Exception('User is not allowed to send invitations for this team', 401); + throw new Exception('User is not allowed to send invitations for this team', 401, Exception::USER_UNAUTHORIZED); } $secret = Auth::tokenGenerator(); @@ -370,7 +370,7 @@ App::post('/v1/teams/:teamId/memberships') try { $membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership)); } catch (Duplicate $th) { - throw new Exception('User has already been invited or is already a member of this team', 409); + throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITATION_ALREADY_EXISTS); } $team->setAttribute('sum', $team->getAttribute('sum', 0) + 1); $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); @@ -383,7 +383,7 @@ App::post('/v1/teams/:teamId/memberships') try { $membership = $dbForProject->createDocument('memberships', $membership); } catch (Duplicate $th) { - throw new Exception('User has already been invited or is already a member of this team', 409); + throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITATION_ALREADY_EXISTS); } } @@ -568,7 +568,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') $isOwner = Authorization::isRole('team:'.$team->getId().'/owner');; if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) - throw new Exception('User is not allowed to modify roles', 401); + throw new Exception('User is not allowed to modify roles', 401, Exception::USER_UNAUTHORIZED); } // Update the roles @@ -743,7 +743,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $membership = $dbForProject->getDocument('memberships', $membershipId); if ($membership->isEmpty()) { - throw new Exception('Invite not found', 404); + throw new Exception('Invite not found', 404, Exception::TEAM_INVITE_NOT_FOUND); } if ($membership->getAttribute('teamId') !== $teamId) { @@ -753,7 +753,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); if ($user->isEmpty()) { - throw new Exception('User not found', 404); + throw new Exception('User not found', 404, Exception::USER_NOT_FOUND); } $team = $dbForProject->getDocument('teams', $teamId); @@ -765,7 +765,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') try { $dbForProject->deleteDocument('memberships', $membership->getId()); } catch (AuthorizationException $exception) { - throw new Exception('Unauthorized permissions', 401, Exception::UNAUTHORIZED_SCOPE); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } catch (\Exception $exception) { throw new Exception('Failed to remove membership from DB', 500); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d0cf5ec650..d102c7a3f4 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -40,6 +40,7 @@ class Exception extends \Exception const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; const USER_SESSION_NOT_FOUND = 'user_session_not_found'; + const USER_UNAUTHORIZED = 'user_unauthorized'; const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; /** OAuth **/ @@ -52,10 +53,14 @@ class Exception extends \Exception const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; /** Teams */ - const TEAM_NOT_FOUND = 'team_not_found'; + const TEAM_NOT_FOUND = 'team_not_found'; + const TEAM_DELETION_FAILED = 'team_deletion_failed'; + const TEAM_INVITATION_ALREADY_EXISTS = 'team_invitation_already_exists'; + const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; /** Membership */ - const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + const MEMBERSHIP_DELETION_FAILED = 'membership_deletion_failed'; /** Avatars */ const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; From c3369dec5056c0ec5f7444399a5b4ca8650de341 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 19:38:15 +0400 Subject: [PATCH 41/95] feat: update error codes in the teams API --- app/config/errors.php | 14 ++++++++++++-- app/controllers/api/teams.php | 10 +++++----- src/Appwrite/Extend/Exception.php | 4 +++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 5b90bfa170..547356b2cd 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -186,8 +186,8 @@ return [ 'description' => 'Failed to delete team from the database.', 'statusCode' => 500, ], - Exception::TEAM_INVITATION_ALREADY_EXISTS => [ - 'name' => Exception::TEAM_INVITATION_ALREADY_EXISTS, + Exception::TEAM_INVITE_ALREADY_EXISTS => [ + 'name' => Exception::TEAM_INVITE_ALREADY_EXISTS, 'description' => 'The current user already has an invitation to this team.', 'statusCode' => 409, ], @@ -196,6 +196,16 @@ return [ 'description' => 'The requested invitation could not be found.', 'statusCode' => 409, ], + Exception::TEAM_INVALID_SECRET => [ + 'name' => Exception::TEAM_INVALID_SECRET, + 'description' => 'The team invitation secret is invalid.', + 'statusCode' => 401, + ], + Exception::TEAM_MEMBERSHIP_MISMATCH => [ + 'name' => Exception::TEAM_MEMBERSHIP_MISMATCH, + 'description' => 'The membership ID does not belong to the team ID.', + 'statusCode' => 404, + ], /** Membership */ diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index bc38a28bd2..c3fc90c056 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -370,7 +370,7 @@ App::post('/v1/teams/:teamId/memberships') try { $membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership)); } catch (Duplicate $th) { - throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITATION_ALREADY_EXISTS); + throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITE_ALREADY_EXISTS); } $team->setAttribute('sum', $team->getAttribute('sum', 0) + 1); $team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team)); @@ -383,7 +383,7 @@ App::post('/v1/teams/:teamId/memberships') try { $membership = $dbForProject->createDocument('memberships', $membership); } catch (Duplicate $th) { - throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITATION_ALREADY_EXISTS); + throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITE_ALREADY_EXISTS); } } @@ -625,7 +625,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($membership->getAttribute('teamId') !== $teamId) { - throw new Exception('Team IDs don\'t match', 404); + throw new Exception('Team IDs don\'t match', 404, Exception::TEAM_MEMBERSHIP_MISMATCH); } $team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId)); @@ -635,7 +635,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if (Auth::hash($secret) !== $membership->getAttribute('secret')) { - throw new Exception('Secret key not valid', 401); + throw new Exception('Secret key not valid', 401, Exception::TEAM_INVALID_SECRET); } if ($userId != $membership->getAttribute('userId')) { @@ -767,7 +767,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') } catch (AuthorizationException $exception) { throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } catch (\Exception $exception) { - throw new Exception('Failed to remove membership from DB', 500); + throw new Exception('Failed to remove membership from DB', 500, Exception::MEMBERSHIP_DELETION_FAILED); } $memberships = $user->getAttribute('memberships', []); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d102c7a3f4..031fe9ec79 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -55,8 +55,10 @@ class Exception extends \Exception /** Teams */ const TEAM_NOT_FOUND = 'team_not_found'; const TEAM_DELETION_FAILED = 'team_deletion_failed'; - const TEAM_INVITATION_ALREADY_EXISTS = 'team_invitation_already_exists'; + const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; + const TEAM_INVALID_SECRET = 'team_invalid_secret'; + const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; /** Membership */ const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; From 7160364902efdeca2277b1b73edf4090823fcf2d Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 19:57:15 +0400 Subject: [PATCH 42/95] feat: update error codes in the teams API --- app/config/errors.php | 5 +++++ app/controllers/api/teams.php | 4 ++-- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 547356b2cd..9fcb97c079 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -206,6 +206,11 @@ return [ 'description' => 'The membership ID does not belong to the team ID.', 'statusCode' => 404, ], + Exception::TEAM_INVITE_MISMATCH => [ + 'name' => Exception::TEAM_INVITE_MISMATCH, + 'description' => 'The invite does not belong to the current user.', + 'statusCode' => 401, + ], /** Membership */ diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index c3fc90c056..9f428ad574 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -639,7 +639,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($userId != $membership->getAttribute('userId')) { - throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401); + throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401, Exception::TEAM_INVITE_MISMATCH); } if ($user->isEmpty()) { @@ -647,7 +647,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($membership->getAttribute('userId') !== $user->getId()) { - throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401); + throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401, Exception::TEAM_INVITE_MISMATCH); } $membership // Attach user to team diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 031fe9ec79..baa42c98d9 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -59,6 +59,7 @@ class Exception extends \Exception const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; const TEAM_INVALID_SECRET = 'team_invalid_secret'; const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; + const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; /** Membership */ const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; From 1ca2cc7bc01321604a59bb15e16d8b5b40d2834b Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 20:12:15 +0400 Subject: [PATCH 43/95] feat: update error codes in the functions API --- app/config/errors.php | 47 ++++++++++++++++++++-- app/controllers/api/functions.php | 66 +++++++++++++++---------------- app/controllers/api/storage.php | 2 +- src/Appwrite/Extend/Exception.php | 15 ++++++- 4 files changed, 92 insertions(+), 38 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 9fcb97c079..cf407f7816 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -273,11 +273,21 @@ return [ 'description' => 'The requested storage device could not be found.', 'statusCode' => 400, ], - Exception::STORAGE_FAILED_TO_DELETE_FILE => [ - 'name' => Exception::STORAGE_FAILED_TO_DELETE_FILE, - 'description' => 'There was an issue deleting the file from the database', + Exception::STORAGE_FILE_DELETION_FAILED => [ + 'name' => Exception::STORAGE_FILE_DELETION_FAILED, + 'description' => 'There was an issue deleting the file from the database.', 'statusCode' => 500, ], + Exception::STORAGE_FILE_EMPTY => [ + 'name' => Exception::STORAGE_FILE_EMPTY, + 'description' => 'Empty file passed to the endpoint.', + 'statusCode' => 400, + ], + Exception::STORAGE_FILE_TYPE_UNSUPPORTED => [ + 'name' => Exception::STORAGE_FILE_TYPE_UNSUPPORTED, + 'description' => 'The file type is not supported.', + 'statusCode' => 400, + ], Exception::STORAGE_FILE_NOT_READABLE => [ 'name' => Exception::STORAGE_FILE_NOT_READABLE, 'description' => 'There was an error reading the file from disk.', @@ -313,4 +323,35 @@ return [ 'description' => 'Failed to save the uploaded file.', 'statusCode' => 500, ], + + /** Functions */ + Exception::FUNCTION_NOT_FOUND => [ + 'name' => Exception::FUNCTION_NOT_FOUND, + 'description' => 'The requested function could not be found.', + 'statusCode' => 404, + ], + Exception::FUNCTION_DELETION_FAILED => [ + 'name' => Exception::FUNCTION_DELETION_FAILED, + 'description' => 'Failed to delete the function from the database.', + 'statusCode' => 500, + ], + + /** Deployments */ + Exception::DEPLOYMENT_NOT_FOUND => [ + 'name' => Exception::DEPLOYMENT_NOT_FOUND, + 'description' => 'The requested deployment could not be found.', + 'statusCode' => 404, + ], + Exception::DEPLOYMENT_DELETION_FAILED => [ + 'name' => Exception::DEPLOYMENT_DELETION_FAILED, + 'description' => 'Failed to delete the deployment from the database.', + 'statusCode' => 500, + ], + + /** Executions */ + Exception::EXECUTION_NOT_FOUND => [ + 'name' => Exception::EXECUTION_NOT_FOUND, + 'description' => 'The requested execution could not be found.', + 'statusCode' => 404, + ], ]; \ No newline at end of file diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 8488b341f0..20c77a12e8 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -12,7 +12,7 @@ use Utopia\Storage\Validator\Upload; use Appwrite\Utopia\Response; use Appwrite\Task\Validator\Cron; use Utopia\App; -use Utopia\Exception; +use Appwrite\Extend\Exception use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; @@ -103,7 +103,7 @@ App::get('/v1/functions') $cursorFunction = $dbForProject->getDocument('functions', $cursor); if ($cursorFunction->isEmpty()) { - throw new Exception("Function '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Function '{$cursor}' for the 'cursor' value not found.", 400, Exception::FUNCTION_NOT_FOUND); } } @@ -168,7 +168,7 @@ App::get('/v1/functions/:functionId') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $response->dynamic($function, Response::MODEL_FUNCTION); @@ -197,7 +197,7 @@ App::get('/v1/functions/:functionId/usage') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $usage = []; @@ -306,7 +306,7 @@ App::put('/v1/functions/:functionId') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $original = $function->getAttribute('schedule', ''); @@ -364,11 +364,11 @@ App::patch('/v1/functions/:functionId/tag') $tag = $dbForProject->getDocument('tags', $tag); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } if ($tag->isEmpty()) { - throw new Exception('Tag not found', 404); + throw new Exception('Tag not found', 404, Exception::DEPLOYMENT_NOT_FOUND); } $schedule = $function->getAttribute('schedule', ''); @@ -416,11 +416,11 @@ App::delete('/v1/functions/:functionId') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } if (!$dbForProject->deleteDocument('functions', $function->getId())) { - throw new Exception('Failed to remove function from DB', 500); + throw new Exception('Failed to remove function from DB', 500, Exception::FUNCTION_DELETION_FAILED); } $deletes @@ -461,7 +461,7 @@ App::post('/v1/functions/:functionId/tags') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $file = $request->getFiles('code'); @@ -471,7 +471,7 @@ App::post('/v1/functions/:functionId/tags') $upload = new Upload(); if (empty($file)) { - throw new Exception('No file sent', 400); + throw new Exception('No file sent', 400, Exception::STORAGE_FILE_EMPTY); } // Make sure we handle a single file and multiple files the same way @@ -480,15 +480,15 @@ App::post('/v1/functions/:functionId/tags') $file['size'] = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; if (!$fileExt->isValid($file['name'])) { // Check if file type is allowed - throw new Exception('File type not allowed', 400); + throw new Exception('File type not allowed', 400, Exception::STORAGE_FILE_TYPE_UNSUPPORTED); } if (!$fileSize->isValid($file['size'])) { // Check if file size is exceeding allowed limit - throw new Exception('File size not allowed', 400); + throw new Exception('File size not allowed', 400, Exception::STORAGE_INVALID_FILE_SIZE); } if (!$upload->isValid($file['tmp_name'])) { - throw new Exception('Invalid file', 403); + throw new Exception('Invalid file', 403, Exception::STORAGE_INVALID_FILE); } // Save to storage @@ -496,7 +496,7 @@ App::post('/v1/functions/:functionId/tags') $path = $device->getPath(\uniqid().'.'.\pathinfo($file['name'], PATHINFO_EXTENSION)); if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move' - throw new Exception('Failed moving file', 500); + throw new Exception('Failed moving file', 500, Exception::STORAGE_FAILED_TO_MOVE_FILE); } $tagId = $dbForProject->getId(); @@ -547,14 +547,14 @@ App::get('/v1/functions/:functionId/tags') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } if (!empty($cursor)) { $cursorTag = $dbForProject->getDocument('tags', $cursor); if ($cursorTag->isEmpty()) { - throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400, Exception::DEPLOYMENT_NOT_FOUND); } } @@ -597,17 +597,17 @@ App::get('/v1/functions/:functionId/tags/:tagId') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $tag = $dbForProject->getDocument('tags', $tagId); if ($tag->getAttribute('functionId') !== $function->getId()) { - throw new Exception('Tag not found', 404); + throw new Exception('Tag not found', 404, Exception::DEPLOYMENT_NOT_FOUND); } if ($tag->isEmpty()) { - throw new Exception('Tag not found', 404); + throw new Exception('Tag not found', 404, Exception::DEPLOYMENT_NOT_FOUND); } $response->dynamic($tag, Response::MODEL_TAG); @@ -637,24 +637,24 @@ App::delete('/v1/functions/:functionId/tags/:tagId') $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $tag = $dbForProject->getDocument('tags', $tagId); if ($tag->getAttribute('functionId') !== $function->getId()) { - throw new Exception('Tag not found', 404); + throw new Exception('Tag not found', 404, Exception::DEPLOYMENT_NOT_FOUND); } if ($tag->isEmpty()) { - throw new Exception('Tag not found', 404); + throw new Exception('Tag not found', 404, Exception::DEPLOYMENT_NOT_FOUND); } $device = Storage::getDevice('functions'); if ($device->delete($tag->getAttribute('path', ''))) { if (!$dbForProject->deleteDocument('tags', $tag->getId())) { - throw new Exception('Failed to remove tag from DB', 500); + throw new Exception('Failed to remove tag from DB', 500, Exception::DEPLOYMENT_DELETION_FAILED); } } @@ -701,23 +701,23 @@ App::post('/v1/functions/:functionId/executions') $function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId)); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $tag = Authorization::skip(fn() => $dbForProject->getDocument('tags', $function->getAttribute('tag'))); if ($tag->getAttribute('functionId') !== $function->getId()) { - throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404); + throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404, Exception::DEPLOYMENT_NOT_FOUND); } if ($tag->isEmpty()) { - throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404); + throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404, Exception::DEPLOYMENT_NOT_FOUND); } $validator = new Authorization('execute'); if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function - throw new Exception($validator->getDescription(), 401); + throw new Exception($validator->getDescription(), 401, Exception::USER_UNAUTHORIZED); } $executionId = $dbForProject->getId(); @@ -800,14 +800,14 @@ App::get('/v1/functions/:functionId/executions') $function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId)); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } if (!empty($cursor)) { $cursorExecution = $dbForProject->getDocument('executions', $cursor); if ($cursorExecution->isEmpty()) { - throw new Exception("Execution '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Execution '{$cursor}' for the 'cursor' value not found.", 400, Exception::EXECUTION_NOT_FOUND); } } @@ -850,17 +850,17 @@ App::get('/v1/functions/:functionId/executions/:executionId') $function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId)); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } $execution = $dbForProject->getDocument('executions', $executionId); if ($execution->getAttribute('functionId') !== $function->getId()) { - throw new Exception('Execution not found', 404); + throw new Exception('Execution not found', 404, Exception::EXECUTION_NOT_FOUND); } if ($execution->isEmpty()) { - throw new Exception('Execution not found', 404); + throw new Exception('Execution not found', 404, Exception::EXECUTION_NOT_FOUND); } $response->dynamic($execution, Response::MODEL_EXECUTION); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 88d76cb69d..bfb014b68f 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -671,7 +671,7 @@ App::delete('/v1/storage/files/:fileId') if ($device->delete($file->getAttribute('path', ''))) { if (!$dbForProject->deleteDocument('files', $fileId)) { - throw new Exception('Failed to remove file from DB', 500, Exception::STORAGE_FAILED_TO_DELETE_FILE); + throw new Exception('Failed to remove file from DB', 500, Exception::STORAGE_FILE_DELETION_FAILED); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index baa42c98d9..cb2863e0c7 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -77,8 +77,10 @@ class Exception extends \Exception /** Storage */ const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; - const STORAGE_FAILED_TO_DELETE_FILE = 'storage_failed_to_delete_file'; + const STORAGE_FILE_DELETION_FAILED = 'storage_file_deletion_failed'; const STORAGE_FILE_NOT_READABLE = 'storage_file_not_readable'; + const STORAGE_FILE_EMPTY = 'storage_file_empty'; + const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; const STORAGE_INVALID_READ_PERMISSIONS = 'storage_invalid_read_permissions'; const STORAGE_INVALID_WRITE_PERMISSIONS = 'storage_invalid_write_permissions'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; @@ -86,6 +88,17 @@ class Exception extends \Exception const STORAGE_FAILED_TO_MOVE_FILE = 'storage_failed_to_move_file'; const STORAGE_FAILED_TO_WRITE_FILE = 'storage_failed_to_write_file'; + /** Functions */ + const FUNCTION_NOT_FOUND = 'function_not_found'; + const FUNCTION_DELETION_FAILED = 'function_deletion_failed'; + + /** Deployments */ + const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; + const DEPLOYMENT_DELETION_FAILED = 'deployment_deletion_failed'; + + /** Execution */ + const EXECUTION_NOT_FOUND = 'execution_not_found'; + /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; const PROJECT_UNKNOWN = 'project_unknown'; From c57d42e686495e864256618ae93a42cbb2065b2a Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 20:12:28 +0400 Subject: [PATCH 44/95] feat: update error codes in the functions API --- app/controllers/api/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 20c77a12e8..ab0a1f5baa 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -12,7 +12,7 @@ use Utopia\Storage\Validator\Upload; use Appwrite\Utopia\Response; use Appwrite\Task\Validator\Cron; use Utopia\App; -use Appwrite\Extend\Exception +use Appwrite\Extend\Exception; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; From 7e200253ea8ce3800d2486319eda6ea32646a349 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 20:50:48 +0400 Subject: [PATCH 45/95] feat: update error codes in the database API --- app/config/errors.php | 20 ++--- app/controllers/api/database.php | 142 +++++++++++++++--------------- app/controllers/api/storage.php | 8 +- src/Appwrite/Extend/Exception.php | 51 ++++++++--- 4 files changed, 126 insertions(+), 95 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index cf407f7816..28220072a5 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -18,6 +18,16 @@ return [ 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', 'statusCode' => 503, ], + Exception::INVALID_READ_PERMISSIONS => [ + 'name' => Exception::INVALID_READ_PERMISSIONS, + 'description' => 'Invalid format for read permissions. Please check the documentation.', + 'statusCode' => 400, + ], + Exception::INVALID_WRITE_PERMISSIONS => [ + 'name' => Exception::INVALID_WRITE_PERMISSIONS, + 'description' => 'Invalid format for write permissions. Please check the documentation.', + 'statusCode' => 400, + ], Exception::UNAUTHORIZED_SCOPE => [ 'name' => Exception::UNAUTHORIZED_SCOPE, 'description' => 'The current user or API key does not have the required scopes to access the requested resource.', @@ -293,16 +303,6 @@ return [ 'description' => 'There was an error reading the file from disk.', 'statusCode' => 500, ], - Exception::STORAGE_INVALID_READ_PERMISSIONS => [ - 'name' => Exception::STORAGE_INVALID_READ_PERMISSIONS, - 'description' => 'Invalid format for read permissions. Please check the documentation.', - 'statusCode' => 400, - ], - Exception::STORAGE_INVALID_WRITE_PERMISSIONS => [ - 'name' => Exception::STORAGE_INVALID_WRITE_PERMISSIONS, - 'description' => 'Invalid format for write permissions. Please check the documentation.', - 'statusCode' => 400, - ], Exception::STORAGE_INVALID_FILE_SIZE => [ 'name' => Exception::STORAGE_INVALID_FILE_SIZE, 'description' => 'The file size is either not valid or exceeds the maximum allowed size.', diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index da3cfc68b0..a2710e9ae4 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1,7 +1,7 @@ getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } if (!empty($format)) { if (!Structure::hasFormat($format, $type)) { - throw new Exception("Format {$format} not available for {$type} attributes.", 400); + throw new Exception("Format {$format} not available for {$type} attributes.", 400, Exception::ATTRIBUTE_FORMAT_UNSUPPORTED); } } // Must throw here since dbForProject->createAttribute is performed by db worker if ($required && $default) { - throw new Exception('Cannot set default value for required attribute', 400); + throw new Exception('Cannot set default value for required attribute', 400, Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED); } if ($array && $default) { - throw new Exception('Cannot set default value for array attributes', 400); + throw new Exception('Cannot set default value for array attributes', 400, Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED); } try { @@ -104,10 +104,10 @@ function createAttribute(string $collectionId, Document $attribute, Response $re $attribute = $dbForProject->createDocument('attributes', $attribute); } catch (DuplicateException $exception) { - throw new Exception('Attribute already exists', 409); + throw new Exception('Attribute already exists', 409, Exception::ATTRIBUTE_ALREADY_EXISTS); } catch (LimitException $exception) { - throw new Exception('Attribute limit exceeded', 400); + throw new Exception('Attribute limit exceeded', 400, Exception::ATTRIBUTE_LIMIT_EXCEEDED); } $dbForProject->deleteCachedDocument('collections', $collectionId); @@ -180,9 +180,9 @@ App::post('/v1/database/collections') $dbForProject->createCollection('collection_' . $collectionId); } catch (DuplicateException $th) { - throw new Exception('Collection already exists', 409); + throw new Exception('Collection already exists', 409, Exception::COLLECTION_ALREADY_EXISTS); } catch (LimitException $th) { - throw new Exception('Collection limit exceeded', 400); + throw new Exception('Collection limit exceeded', 400, Exception::COLLECTION_LIMIT_EXCEEDED); } $audits @@ -225,7 +225,7 @@ App::get('/v1/database/collections') $cursorCollection = $dbForProject->getDocument('collections', $cursor); if ($cursorCollection->isEmpty()) { - throw new Exception("Collection '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Collection '{$cursor}' for the 'cursor' value not found.", 400, Exception::COLLECTION_NOT_FOUND); } } @@ -265,7 +265,7 @@ App::get('/v1/database/collections/:collectionId') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $usage->setParam('database.collections.read', 1); @@ -405,7 +405,7 @@ App::get('/v1/database/:collectionId/usage') $collection = $dbForProject->getCollection('collection_' . $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $usage = []; @@ -516,7 +516,7 @@ App::get('/v1/database/collections/:collectionId/logs') $collection = $dbForProject->getCollection('collection_' . $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $audit = new Audit($dbForProject); @@ -605,7 +605,7 @@ App::put('/v1/database/collections/:collectionId') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $read ??= $collection->getRead() ?? []; // By default inherit read permissions @@ -624,10 +624,10 @@ App::put('/v1/database/collections/:collectionId') ); } catch (AuthorizationException $exception) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } catch (StructureException $exception) { - throw new Exception('Bad structure. '.$exception->getMessage(), 400); + throw new Exception('Bad structure. '.$exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } $usage->setParam('database.collections.update', 1); @@ -669,11 +669,11 @@ App::delete('/v1/database/collections/:collectionId') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } if (!$dbForProject->deleteDocument('collections', $collectionId)) { - throw new Exception('Failed to remove collection from DB', 500); + throw new Exception('Failed to remove collection from DB', 500, Exception::COLLECTION_DELETION_FAILED); } $dbForProject->deleteCachedCollection('collection_' . $collectionId); @@ -731,7 +731,7 @@ App::post('/v1/database/collections/:collectionId/attributes/string') // Ensure attribute default is within required size $validator = new Text($size); if (!is_null($default) && !$validator->isValid($default)) { - throw new Exception($validator->getDescription(), 400); + throw new Exception($validator->getDescription(), 400, Exception::ATTRIBUTE_VALUE_INVALID); } $attribute = createAttribute($collectionId, new Document([ @@ -823,14 +823,14 @@ App::post('/v1/database/collections/:collectionId/attributes/enum') foreach ($elements as $element) { $length = \strlen($element); if ($length === 0) { - throw new Exception('Each enum element must not be empty', 400); + throw new Exception('Each enum element must not be empty', 400, Exception::ATTRIBUTE_VALUE_INVALID); } $size = ($length > $size) ? $length : $size; } if (!is_null($default) && !in_array($default, $elements)) { - throw new Exception('Default value not found in elements', 400); + throw new Exception('Default value not found in elements', 400, Exception::ATTRIBUTE_VALUE_INVALID); } $attribute = createAttribute($collectionId, new Document([ @@ -966,13 +966,13 @@ App::post('/v1/database/collections/:collectionId/attributes/integer') $max = (is_null($max)) ? PHP_INT_MAX : \intval($max); if ($min > $max) { - throw new Exception('Minimum value must be lesser than maximum value', 400); + throw new Exception('Minimum value must be lesser than maximum value', 400, Exception::ATTRIBUTE_VALUE_INVALID); } $validator = new Range($min, $max, Database::VAR_INTEGER); if (!is_null($default) && !$validator->isValid($default)) { - throw new Exception($validator->getDescription(), 400); + throw new Exception($validator->getDescription(), 400, Exception::ATTRIBUTE_VALUE_INVALID); } $size = $max > 2147483647 ? 8 : 4; // Automatically create BigInt depending on max value @@ -1037,7 +1037,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float') $max = (is_null($max)) ? PHP_FLOAT_MAX : \floatval($max); if ($min > $max) { - throw new Exception('Minimum value must be lesser than maximum value', 400); + throw new Exception('Minimum value must be lesser than maximum value', 400, Exception::ATTRIBUTE_VALUE_INVALID); } // Ensure default value is a float @@ -1048,7 +1048,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float') $validator = new Range($min, $max, Database::VAR_FLOAT); if (!is_null($default) && !$validator->isValid($default)) { - throw new Exception($validator->getDescription(), 400); + throw new Exception($validator->getDescription(), 400, Exception::ATTRIBUTE_VALUE_INVALID); } $attribute = createAttribute($collectionId, new Document([ @@ -1138,7 +1138,7 @@ App::get('/v1/database/collections/:collectionId/attributes') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $attributes = $collection->getAttribute('attributes'); @@ -1182,13 +1182,13 @@ App::get('/v1/database/collections/:collectionId/attributes/:key') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $attribute = $dbForProject->getDocument('attributes', $collectionId.'_'.$key); if ($attribute->isEmpty()) { - throw new Exception('Attribute not found', 404); + throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND); } // Select response model based on type and format @@ -1244,13 +1244,13 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $attribute = $dbForProject->getDocument('attributes', $collectionId.'_'.$key); if ($attribute->isEmpty()) { - throw new Exception('Attribute not found', 404); + throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND); } // Only update status if removing available attribute @@ -1332,7 +1332,7 @@ App::post('/v1/database/collections/:collectionId/indexes') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $count = $dbForProject->count('indexes', [ @@ -1342,7 +1342,7 @@ App::post('/v1/database/collections/:collectionId/indexes') $limit = 64 - MariaDB::getNumberOfDefaultIndexes(); if ($count >= $limit) { - throw new Exception('Index limit exceeded', 400); + throw new Exception('Index limit exceeded', 400, Exception::INDEX_LIMIT_EXCEEDED); } // Convert Document[] to array of attribute metadata @@ -1356,7 +1356,7 @@ App::post('/v1/database/collections/:collectionId/indexes') $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); if ($attributeIndex === false) { - throw new Exception('Unknown attribute: ' . $attribute, 400); + throw new Exception('Unknown attribute: ' . $attribute, 400, Exception::ATTRIBUTE_UNKNOWN); } $attributeStatus = $oldAttributes[$attributeIndex]['status']; @@ -1365,7 +1365,7 @@ App::post('/v1/database/collections/:collectionId/indexes') // ensure attribute is available if ($attributeStatus !== 'available') { - throw new Exception ('Attribute not available: ' . $oldAttributes[$attributeIndex]['key'], 400); + throw new Exception ('Attribute not available: ' . $oldAttributes[$attributeIndex]['key'], 400, Exception::ATTRIBUTE_NOT_AVAILABLE); } // set attribute size as index length only for strings @@ -1384,7 +1384,7 @@ App::post('/v1/database/collections/:collectionId/indexes') 'orders' => $orders, ])); } catch (DuplicateException $th) { - throw new Exception('Index already exists', 409); + throw new Exception('Index already exists', 409, Exception::INDEX_ALREADY_EXISTS); } $dbForProject->deleteCachedDocument('collections', $collectionId); @@ -1429,7 +1429,7 @@ App::get('/v1/database/collections/:collectionId/indexes') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $indexes = $collection->getAttribute('indexes'); @@ -1465,7 +1465,7 @@ App::get('/v1/database/collections/:collectionId/indexes/:key') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $indexes = $collection->getAttribute('indexes'); @@ -1474,7 +1474,7 @@ App::get('/v1/database/collections/:collectionId/indexes/:key') $indexIndex = array_search($key, array_column($indexes, 'key')); if ($indexIndex === false) { - throw new Exception('Index not found', 404); + throw new Exception('Index not found', 404, Exception::INDEX_NOT_FOUND); } $index = new Document([\array_merge($indexes[$indexIndex], [ @@ -1516,13 +1516,13 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $index = $dbForProject->getDocument('indexes', $collectionId.'_'.$key); if (empty($index->getId())) { - throw new Exception('Index not found', 404); + throw new Exception('Index not found', 404, Exception::INDEX_NOT_FOUND); } // Only update status if removing available index @@ -1589,11 +1589,11 @@ App::post('/v1/database/collections/:collectionId/documents') $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array if (empty($data)) { - throw new Exception('Missing payload', 400); + throw new Exception('Missing payload', 400, Exception::DOCUMENT_MISSING_PAYLOAD); } if (isset($data['$id'])) { - throw new Exception('$id is not allowed for creating new documents, try update instead', 400); + throw new Exception('$id is not allowed for creating new documents, try update instead', 400, Exception::DOCUMENT_INVALID_STRUCTURE); } /** @@ -1605,7 +1605,7 @@ App::post('/v1/database/collections/:collectionId/documents') if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } } @@ -1613,7 +1613,7 @@ App::post('/v1/database/collections/:collectionId/documents') if ($collection->getAttribute('permission') === 'collection') { $validator = new Authorization('write'); if (!$validator->isValid($collection->getWrite())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1628,12 +1628,12 @@ App::post('/v1/database/collections/:collectionId/documents') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($data['$read'] as $read) { if (!Authorization::isRole($read)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); } } foreach ($data['$write'] as $write) { if (!Authorization::isRole($write)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); } } } @@ -1648,10 +1648,10 @@ App::post('/v1/database/collections/:collectionId/documents') $document->setAttribute('$collection', $collectionId); } catch (StructureException $exception) { - throw new Exception($exception->getMessage(), 400); + throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } catch (DuplicateException $exception) { - throw new Exception('Document already exists', 409); + throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } $events->setParam('collection', $collection->getArrayCopy()); @@ -1709,7 +1709,7 @@ App::get('/v1/database/collections/:collectionId/documents') if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } } @@ -1717,7 +1717,7 @@ App::get('/v1/database/collections/:collectionId/documents') if ($collection->getAttribute('permission') === 'collection') { $validator = new Authorization('read'); if (!$validator->isValid($collection->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1725,7 +1725,7 @@ App::get('/v1/database/collections/:collectionId/documents') $query = Query::parse($query); if (\count($query->getValues()) > 100) { - throw new Exception("You cannot use more than 100 query values on attribute '{$query->getAttribute()}'", 400); + throw new Exception("You cannot use more than 100 query values on attribute '{$query->getAttribute()}'", 400, Exception::QUERY_LIMIT_EXCEEDED); } return $query; @@ -1734,7 +1734,7 @@ App::get('/v1/database/collections/:collectionId/documents') if (!empty($queries)) { $validator = new QueriesValidator(new QueryValidator($collection->getAttribute('attributes', [])), $collection->getAttribute('indexes', []), true); if (!$validator->isValid($queries)) { - throw new Exception($validator->getDescription(), 400); + throw new Exception($validator->getDescription(), 400, Exception::QUERY_INVALID); } } @@ -1745,7 +1745,7 @@ App::get('/v1/database/collections/:collectionId/documents') : $dbForProject->getDocument('collection_' . $collectionId, $cursor); if ($cursorDocument->isEmpty()) { - throw new Exception("Document '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Document '{$cursor}' for the 'cursor' value not found.", 400, Exception::DOCUMENT_NOT_FOUND); } } @@ -1803,7 +1803,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId') if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } } @@ -1811,7 +1811,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId') if ($collection->getAttribute('permission') === 'collection') { $validator = new Authorization('read'); if (!$validator->isValid($collection->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1828,7 +1828,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId') $document->setAttribute('$collection', $collectionId); if ($document->isEmpty()) { - throw new Exception('No document found', 404); + throw new Exception('No document found', 404, Exception::DOCUMENT_NOT_FOUND); } $usage @@ -1868,13 +1868,13 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs') $collection = $dbForProject->getDocument('collections', $collectionId); if ($collection->isEmpty()) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } $document = $dbForProject->getDocument('collection_' . $collectionId, $documentId); if ($document->isEmpty()) { - throw new Exception('No document found', 404); + throw new Exception('No document found', 404, Exception::DOCUMENT_NOT_FOUND); } $audit = new Audit($dbForProject); @@ -1969,7 +1969,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } } @@ -1977,7 +1977,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') if ($collection->getAttribute('permission') === 'collection') { $validator = new Authorization('write'); if (!$validator->isValid($collection->getWrite())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } $document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collectionId, $documentId)); @@ -1987,17 +1987,17 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') if ($document->isEmpty()) { - throw new Exception('Document not found', 404); + throw new Exception('Document not found', 404, Exception::DOCUMENT_NOT_FOUND); } $data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array if (empty($data)) { - throw new Exception('Missing payload', 400); + throw new Exception('Missing payload', 400, Exception::DOCUMENT_MISSING_PAYLOAD); } if (!\is_array($data)) { - throw new Exception('Data param should be a valid JSON object', 400); + throw new Exception('Data param should be a valid JSON object', 400, Exception::DOCUMENT_INVALID_STRUCTURE); } $data = \array_merge($document->getArrayCopy(), $data); @@ -2013,12 +2013,12 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($data['$read'] as $read) { if (!Authorization::isRole($read)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); } } foreach ($data['$write'] as $write) { if (!Authorization::isRole($write)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); } } } @@ -2036,13 +2036,13 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') $document->setAttribute('$collection', $collectionId); } catch (AuthorizationException $exception) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } catch (DuplicateException $exception) { - throw new Exception('Document already exists', 409); + throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } catch (StructureException $exception) { - throw new Exception($exception->getMessage(), 400); + throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } $events->setParam('collection', $collection->getArrayCopy()); @@ -2097,7 +2097,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId') if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception('Collection not found', 404); + throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } } @@ -2105,7 +2105,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId') if ($collection->getAttribute('permission') === 'collection') { $validator = new Authorization('write'); if (!$validator->isValid($collection->getWrite())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -2117,7 +2117,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId') } if ($document->isEmpty()) { - throw new Exception('No document found', 404); + throw new Exception('No document found', 404, Exception::DOCUMENT_NOT_FOUND); } if ($collection->getAttribute('permission') === 'collection') { diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index bfb014b68f..0dbadb6aa8 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -68,12 +68,12 @@ App::post('/v1/storage/files') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_READ_PERMISSIONS); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_WRITE_PERMISSIONS); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); } } } @@ -602,12 +602,12 @@ App::put('/v1/storage/files/:fileId') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_READ_PERMISSIONS); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::STORAGE_INVALID_WRITE_PERMISSIONS); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); } } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index cb2863e0c7..fd0b678793 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -81,8 +81,6 @@ class Exception extends \Exception const STORAGE_FILE_NOT_READABLE = 'storage_file_not_readable'; const STORAGE_FILE_EMPTY = 'storage_file_empty'; const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; - const STORAGE_INVALID_READ_PERMISSIONS = 'storage_invalid_read_permissions'; - const STORAGE_INVALID_WRITE_PERMISSIONS = 'storage_invalid_write_permissions'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; const STORAGE_INVALID_FILE = 'storage_invalid_file'; const STORAGE_FAILED_TO_MOVE_FILE = 'storage_failed_to_move_file'; @@ -99,23 +97,56 @@ class Exception extends \Exception /** Execution */ const EXECUTION_NOT_FOUND = 'execution_not_found'; + /** Collections */ + const COLLECTION_NOT_FOUND = 'collection_not_found'; + const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; + const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; + const COLLECTION_DELETION_FAILED = 'collection_deletion_failed'; + + /** Documents */ + const DOCUMENT_NOT_FOUND = 'document_not_found'; + const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; + const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; + const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; + + /** Attribute */ + const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; + const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; + const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; + const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; + const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; + const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; + const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; + const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; + + /** Indexes */ + const INDEX_NOT_FOUND = 'index_not_found'; + const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; + const INDEX_ALREADY_EXISTS = 'index_already_exists'; + + /** Query limit exceeded */ + const QUERY_LIMIT_EXCEEDED = 'query_limit_exceeded'; + const QUERY_INVALID = 'query_invalid'; + /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; const PROJECT_UNKNOWN = 'project_unknown'; /** API */ - const UNKNOWN = 'unknown'; - const UNKNOWN_ORIGIN = 'unknown_origin'; - const SERVICE_DISABLED = 'service_disabled'; - const UNAUTHORIZED_SCOPE = 'unauthorized_scope'; - const STORAGE_ERROR = 'storage_error'; - const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; - const SMTP_DISABLED = 'smtp_disabled'; + const DEFAULT = 'default'; + const UNKNOWN_ORIGIN = 'unknown_origin'; + const SERVICE_DISABLED = 'service_disabled'; + const INVALID_READ_PERMISSIONS = 'invalid_read_permissions'; + const INVALID_WRITE_PERMISSIONS = 'invalid_write_permissions'; + const UNAUTHORIZED_SCOPE = 'unauthorized_scope'; + const STORAGE_ERROR = 'storage_error'; + const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; + const SMTP_DISABLED = 'smtp_disabled'; private $errorCode = ''; - public function __construct(string $message, int $code = 0, string $errorCode = Exception::UNKNOWN, \Throwable $previous = null) + public function __construct(string $message, int $code = 0, string $errorCode = Exception::DEFAULT, \Throwable $previous = null) { $this->errorCode = $errorCode; From d7f31231e3120d1cfcd9e474ea300c31d32ed62d Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 20:56:30 +0400 Subject: [PATCH 46/95] feat: update error codes in the database API --- app/config/errors.php | 116 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index 28220072a5..3359dad095 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -5,6 +5,7 @@ */ use Appwrite\Extend\Exception; +use PhpParser\Node\Expr; return [ /** General Errors */ @@ -354,4 +355,119 @@ return [ 'description' => 'The requested execution could not be found.', 'statusCode' => 404, ], + + /** Collections */ + Exception::COLLECTION_NOT_FOUND => [ + 'name' => Exception::COLLECTION_NOT_FOUND, + 'description' => 'The requested collection could not be found.', + 'statusCode' => 404, + ], + Exception::COLLECTION_ALREADY_EXISTS => [ + 'name' => Exception::COLLECTION_ALREADY_EXISTS, + 'description' => 'The collection already exists.', + 'statusCode' => 400, + ], + Exception::COLLECTION_LIMIT_EXCEEDED => [ + 'name' => Exception::COLLECTION_LIMIT_EXCEEDED, + 'description' => 'The maximum number of collections has been reached.', + 'statusCode' => 400, + ], + Exception::COLLECTION_DELETION_FAILED => [ + 'name' => Exception::COLLECTION_DELETION_FAILED, + 'description' => 'Failed to delete the collection from the database.', + 'statusCode' => 500, + ], + + /** Documents */ + Exception::DOCUMENT_NOT_FOUND => [ + 'name' => Exception::DOCUMENT_NOT_FOUND, + 'description' => 'The requested document could not be found.', + 'statusCode' => 404, + ], + Exception::DOCUMENT_INVALID_STRUCTURE => [ + 'name' => Exception::DOCUMENT_INVALID_STRUCTURE, + 'description' => 'The document structure is invalid.', + 'statusCode' => 400, + ], + Exception::DOCUMENT_MISSING_PAYLOAD => [ + 'name' => Exception::DOCUMENT_MISSING_PAYLOAD, + 'description' => 'The document payload is missing.', + 'statusCode' => 400, + ], + Exception::DOCUMENT_ALREADY_EXISTS => [ + 'name' => Exception::DOCUMENT_ALREADY_EXISTS, + 'description' => 'The document already exists.', + 'statusCode' => 400, + ], + + /** Attributes */ + Exception::ATTRIBUTE_NOT_FOUND => [ + 'name' => Exception::ATTRIBUTE_NOT_FOUND, + 'description' => 'The requested attribute could not be found.', + 'statusCode' => 404, + ], + Exception::ATTRIBUTE_UNKNOWN => [ + 'name' => Exception::ATTRIBUTE_UNKNOWN, + 'description' => 'The requested attribute could not be found.', + 'statusCode' => 404, + ], + Exception::ATTRIBUTE_NOT_AVAILABLE => [ + 'name' => Exception::ATTRIBUTE_NOT_AVAILABLE, + 'description' => 'The requested attribute is not available.', + 'statusCode' => 404, + ], + Exception::ATTRIBUTE_FORMAT_UNSUPPORTED => [ + 'name' => Exception::ATTRIBUTE_FORMAT_UNSUPPORTED, + 'description' => 'The requested attribute format is not supported.', + 'statusCode' => 400, + ], + Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED => [ + 'name' => Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, + 'description' => 'The requested attribute default value is not supported.', + 'statusCode' => 400, + ], + Exception::ATTRIBUTE_ALREADY_EXISTS => [ + 'name' => Exception::ATTRIBUTE_ALREADY_EXISTS, + 'description' => 'The attribute already exists.', + 'statusCode' => 400, + ], + Exception::ATTRIBUTE_LIMIT_EXCEEDED => [ + 'name' => Exception::ATTRIBUTE_LIMIT_EXCEEDED, + 'description' => 'The maximum number of attributes has been reached.', + 'statusCode' => 400, + ], + Exception::ATTRIBUTE_VALUE_INVALID => [ + 'name' => Exception::ATTRIBUTE_VALUE_INVALID, + 'description' => 'The attribute value is invalid.', + 'statusCode' => 400, + ], + + /** Indexes */ + Exception::INDEX_NOT_FOUND => [ + 'name' => Exception::INDEX_NOT_FOUND, + 'description' => 'The requested index could not be found.', + 'statusCode' => 404, + ], + Exception::INDEX_LIMIT_EXCEEDED => [ + 'name' => Exception::INDEX_LIMIT_EXCEEDED, + 'description' => 'The maximum number of indexes has been reached.', + 'statusCode' => 400, + ], + Exception::INDEX_ALREADY_EXISTS => [ + 'name' => Exception::INDEX_ALREADY_EXISTS, + 'description' => 'The index already exists.', + 'statusCode' => 400, + ], + + /** Query */ + Exception::QUERY_LIMIT_EXCEEDED => [ + 'name' => Exception::QUERY_LIMIT_EXCEEDED, + 'description' => 'The maximum number of results has been reached.', + 'statusCode' => 400, + ], + Exception::QUERY_INVALID => [ + 'name' => Exception::QUERY_INVALID, + 'description' => 'The query is invalid.', + 'statusCode' => 400, + ], ]; \ No newline at end of file From 44c923144a992aeaeeb5bf8ac039c5b82b1943e3 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 21:11:02 +0400 Subject: [PATCH 47/95] feat: update error codes in the projectsAPI --- app/controllers/api/projects.php | 102 +++++++++++++++--------------- src/Appwrite/Extend/Exception.php | 18 +++++- 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index b65eb5db7b..cd2e0435f5 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -17,7 +17,7 @@ use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Domains\Domain; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\Integer; @@ -29,7 +29,7 @@ App::init(function ($project) { /** @var Utopia\Database\Document $project */ if ($project->getId() !== 'console') { - throw new Exception('Access to this API is forbidden.', 401); + throw new Exception('Access to this API is forbidden.', 401, Exception::ACCESS_FORBIDDEN); } }, ['project'], 'projects'); @@ -66,7 +66,7 @@ App::post('/v1/projects') $team = $dbForConsole->getDocument('teams', $teamId); if ($team->isEmpty()) { - throw new Exception('Team not found', 404); + throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND); } $auth = Config::getParam('auth', []); @@ -172,7 +172,7 @@ App::get('/v1/projects') $cursorProject = $dbForConsole->getDocument('projects', $cursor); if ($cursorProject->isEmpty()) { - throw new Exception("Project '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Project '{$cursor}' for the 'cursor' value not found.", 400, Exception::PROJECT_NOT_FOUND); } } @@ -211,7 +211,7 @@ App::get('/v1/projects/:projectId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $response->dynamic($project, Response::MODEL_PROJECT); @@ -242,7 +242,7 @@ App::get('/v1/projects/:projectId/usage') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $usage = []; @@ -361,7 +361,7 @@ App::patch('/v1/projects/:projectId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project @@ -404,7 +404,7 @@ App::patch('/v1/projects/:projectId/service') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $services = $project->getAttribute('services', []); @@ -438,7 +438,7 @@ App::patch('/v1/projects/:projectId/oauth2') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $providers = $project->getAttribute('providers', []); @@ -471,7 +471,7 @@ App::patch('/v1/projects/:projectId/auth/limit') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $auths = $project->getAttribute('auths', []); @@ -509,7 +509,7 @@ App::patch('/v1/projects/:projectId/auth/:method') $status = ($status === '1' || $status === 'true' || $status === 1 || $status === true); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $auths = $project->getAttribute('auths', []); @@ -542,13 +542,13 @@ App::delete('/v1/projects/:projectId') /** @var Appwrite\Event\Event $deletes */ if (!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password - throw new Exception('Invalid credentials', 401); + throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); } $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $deletes @@ -557,11 +557,11 @@ App::delete('/v1/projects/:projectId') ; if (!$dbForConsole->deleteDocument('teams', $project->getAttribute('teamId', null))) { - throw new Exception('Failed to remove project team from DB', 500); + throw new Exception('Failed to remove project team from DB', 500, Exception::COLLECTION_DELETION_FAILED); } if (!$dbForConsole->deleteDocument('projects', $projectId)) { - throw new Exception('Failed to remove project from DB', 500); + throw new Exception('Failed to remove project from DB', 500, Exception::COLLECTION_DELETION_FAILED); } $response->noContent(); @@ -595,7 +595,7 @@ App::post('/v1/projects/:projectId/webhooks') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $security = ($security === '1' || $security === 'true' || $security === 1 || $security === true); @@ -641,7 +641,7 @@ App::get('/v1/projects/:projectId/webhooks') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $webhooks = $dbForConsole->find('webhooks', [ @@ -675,7 +675,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $webhook = $dbForConsole->findOne('webhooks', [ @@ -684,7 +684,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId') ]); if ($webhook === false || $webhook->isEmpty()) { - throw new Exception('Webhook not found', 404); + throw new Exception('Webhook not found', 404, Exception::WEBHOOK_NOT_FOUND); } $response->dynamic($webhook, Response::MODEL_WEBHOOK); @@ -717,7 +717,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $security = ($security === '1' || $security === 'true' || $security === 1 || $security === true); @@ -728,7 +728,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ]); if ($webhook === false || $webhook->isEmpty()) { - throw new Exception('Webhook not found', 404); + throw new Exception('Webhook not found', 404), Exception::WEBHOOK_NOT_FOUND; } $webhook @@ -767,7 +767,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $webhook = $dbForConsole->findOne('webhooks', [ @@ -776,7 +776,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') ]); if($webhook === false || $webhook->isEmpty()) { - throw new Exception('Webhook not found', 404); + throw new Exception('Webhook not found', 404, Exception::WEBHOOK_NOT_FOUND); } $dbForConsole->deleteDocument('webhooks', $webhook->getId()); @@ -810,7 +810,7 @@ App::post('/v1/projects/:projectId/keys') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $key = new Document([ @@ -851,7 +851,7 @@ App::get('/v1/projects/:projectId/keys') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $keys = $dbForConsole->find('keys', [ @@ -885,7 +885,7 @@ App::get('/v1/projects/:projectId/keys/:keyId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $key = $dbForConsole->findOne('keys', [ @@ -894,7 +894,7 @@ App::get('/v1/projects/:projectId/keys/:keyId') ]); if ($key === false || $key->isEmpty()) { - throw new Exception('Key not found', 404); + throw new Exception('Key not found', 404, Exception::KEY_NOT_FOUND); } $response->dynamic($key, Response::MODEL_KEY); @@ -923,7 +923,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $key = $dbForConsole->findOne('keys', [ @@ -932,7 +932,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') ]); if ($key === false || $key->isEmpty()) { - throw new Exception('Key not found', 404); + throw new Exception('Key not found', 404, Exception::KEY_NOT_FOUND); } $key @@ -967,7 +967,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $key = $dbForConsole->findOne('keys', [ @@ -976,7 +976,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId') ]); if($key === false || $key->isEmpty()) { - throw new Exception('Key not found', 404); + throw new Exception('Key not found', 404, Exception::KEY_NOT_FOUND); } $dbForConsole->deleteDocument('keys', $key->getId()); @@ -1013,7 +1013,7 @@ App::post('/v1/projects/:projectId/platforms') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $platform = new Document([ @@ -1058,7 +1058,7 @@ App::get('/v1/projects/:projectId/platforms') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $platforms = $dbForConsole->find('platforms', [ @@ -1092,7 +1092,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $platform = $dbForConsole->findOne('platforms', [ @@ -1101,7 +1101,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId') ]); if ($platform === false || $platform->isEmpty()) { - throw new Exception('Platform not found', 404); + throw new Exception('Platform not found', 404, Exception::PLATFORM_NOT_FOUND); } $response->dynamic($platform, Response::MODEL_PLATFORM); @@ -1132,7 +1132,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $platform = $dbForConsole->findOne('platforms', [ @@ -1141,7 +1141,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId') ]); if ($platform === false || $platform->isEmpty()) { - throw new Exception('Platform not found', 404); + throw new Exception('Platform not found', 404, Exception::PLATFORM_NOT_FOUND); } $platform @@ -1179,7 +1179,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $platform = $dbForConsole->findOne('platforms', [ @@ -1188,7 +1188,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') ]); if ($platform === false || $platform->isEmpty()) { - throw new Exception('Platform not found', 404); + throw new Exception('Platform not found', 404, Exception::PLATFORM_NOT_FOUND); } $dbForConsole->deleteDocument('platforms', $platformId); @@ -1221,7 +1221,7 @@ App::post('/v1/projects/:projectId/domains') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $document = $dbForConsole->findOne('domains', [ @@ -1230,13 +1230,13 @@ App::post('/v1/projects/:projectId/domains') ]); if ($document && !$document->isEmpty()) { - throw new Exception('Domain already exists', 409); + throw new Exception('Domain already exists', 409, Exception::DOMAIN_ALREADY_EXISTS); } $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); if (!$target->isKnown() || $target->isTest()) { - throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500); + throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500, Exception::DOMAIN_UNREACHABLE); } $domain = new Domain($domain); @@ -1282,7 +1282,7 @@ App::get('/v1/projects/:projectId/domains') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $domains = $dbForConsole->find('domains', [ @@ -1316,7 +1316,7 @@ App::get('/v1/projects/:projectId/domains/:domainId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $domain = $dbForConsole->findOne('domains', [ @@ -1325,7 +1325,7 @@ App::get('/v1/projects/:projectId/domains/:domainId') ]); if ($domain === false || $domain->isEmpty()) { - throw new Exception('Domain not found', 404); + throw new Exception('Domain not found', 404, Exception::DOMAIN_NOT_FOUND); } $response->dynamic($domain, Response::MODEL_DOMAIN); @@ -1352,7 +1352,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $domain = $dbForConsole->findOne('domains', [ @@ -1361,13 +1361,13 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') ]); if ($domain === false || $domain->isEmpty()) { - throw new Exception('Domain not found', 404); + throw new Exception('Domain not found', 404, Exception::DOMAIN_NOT_FOUND); } $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); if (!$target->isKnown() || $target->isTest()) { - throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500); + throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500, Exception::DOMAIN_UNREACHABLE); } if ($domain->getAttribute('verification') === true) { @@ -1377,7 +1377,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $validator = new CNAME($target->get()); // Verify Domain with DNS records if (!$validator->isValid($domain->getAttribute('domain', ''))) { - throw new Exception('Failed to verify domain', 401); + throw new Exception('Failed to verify domain', 401, Exception::DOMAIN_VERIFICATION_FAILED); } @@ -1414,7 +1414,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId') $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { - throw new Exception('Project not found', 404); + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } $domain = $dbForConsole->findOne('domains', [ @@ -1423,7 +1423,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId') ]); if ($domain === false || $domain->isEmpty()) { - throw new Exception('Domain not found', 404); + throw new Exception('Domain not found', 404, Exception::DOMAIN_NOT_FOUND); } $dbForConsole->deleteDocument('domains', $domain->getId()); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index fd0b678793..ccab54662b 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -132,8 +132,24 @@ class Exception extends \Exception const PROJECT_NOT_FOUND = 'project_not_found'; const PROJECT_UNKNOWN = 'project_unknown'; - /** API */ + /** Webhooks */ + const WEBHOOK_NOT_FOUND = 'webhook_not_found'; + + /** Keys */ + const KEY_NOT_FOUND = 'key_not_found'; + + /** Platform */ + const PLATFORM_NOT_FOUND = 'platform_not_found'; + + /** Domain */ + const DOMAIN_NOT_FOUND = 'domain_not_found'; + const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; + const DOMAIN_UNREACHABLE = 'domain_unreachable'; + const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; + + /** General */ const DEFAULT = 'default'; + const ACCESS_FORBIDDEN = 'access_forbidden'; const UNKNOWN_ORIGIN = 'unknown_origin'; const SERVICE_DISABLED = 'service_disabled'; const INVALID_READ_PERMISSIONS = 'invalid_read_permissions'; From 11cb9b9dd9c0ffc2917226a07eb3d5ca0888f5a3 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 21:11:31 +0400 Subject: [PATCH 48/95] feat: update error codes in the projects API --- app/controllers/api/projects.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index cd2e0435f5..893300d9b2 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -728,7 +728,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ]); if ($webhook === false || $webhook->isEmpty()) { - throw new Exception('Webhook not found', 404), Exception::WEBHOOK_NOT_FOUND; + throw new Exception('Webhook not found', 404, Exception::WEBHOOK_NOT_FOUND); } $webhook From 78a4091f62cd7152c90705b94a6d3691b4d45aa8 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 21:13:14 +0400 Subject: [PATCH 49/95] feat: update error codes in the projects API --- app/config/errors.php | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index 3359dad095..c92e001924 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -61,6 +61,41 @@ return [ 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', 'statusCode' => 400, ], + Exception::WEBHOOK_NOT_FOUND => [ + 'name' => Exception::WEBHOOK_NOT_FOUND, + 'description' => 'The requested webhook could not be found.', + 'statusCode' => 404, + ], + Exception::KEY_NOT_FOUND => [ + 'name' => Exception::KEY_NOT_FOUND, + 'description' => 'The requested key could not be found.', + 'statusCode' => 404, + ], + Exception::PLATFORM_NOT_FOUND => [ + 'name' => Exception::PLATFORM_NOT_FOUND, + 'description' => 'The requested platform could not be found.', + 'statusCode' => 404, + ], + Exception::DOMAIN_NOT_FOUND => [ + 'name' => Exception::DOMAIN_NOT_FOUND, + 'description' => 'The requested domain could not be found.', + 'statusCode' => 404, + ], + Exception::DOMAIN_ALREADY_EXISTS => [ + 'name' => Exception::DOMAIN_ALREADY_EXISTS, + 'description' => 'The requested domain already exists.', + 'statusCode' => 409, + ], + Exception::DOMAIN_UNREACHABLE => [ + 'name' => Exception::DOMAIN_UNREACHABLE, + 'description' => 'The requested domain is not reachable.', + 'statusCode' => 503, + ], + Exception::DOMAIN_VERIFICATION_FAILED => [ + 'name' => Exception::DOMAIN_VERIFICATION_FAILED, + 'description' => 'The requested domain verification failed.', + 'statusCode' => 503, + ], /** User Errors */ Exception::USER_COUNT_EXCEEDED => [ From 53807ab47c4a6abdedf29b572def9446e3ab4184 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 21:21:47 +0400 Subject: [PATCH 50/95] feat: update error codes in the health API --- app/controllers/api/health.php | 14 +++++++------- src/Appwrite/Extend/Exception.php | 9 ++++++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index bcfbbd20ce..fdc8101f58 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -2,7 +2,7 @@ use Appwrite\Utopia\Response; use Utopia\App; -use Utopia\Exception; +use Appwrite\Extend\Exception; use Utopia\Storage\Device\Local; use Utopia\Storage\Storage; use Appwrite\ClamAV\Network; @@ -75,7 +75,7 @@ App::get('/v1/health/db') $statement->execute(); } catch (Exception $_e) { - throw new Exception('Database is not available', 500); + throw new Exception('Database is not available', 500, Exception::DATABASE_NOT_AVAILABLE); } $output = [ @@ -109,7 +109,7 @@ App::get('/v1/health/cache') $redis = $utopia->getResource('cache'); if (!$redis->ping(true)) { - throw new Exception('Cache is not available', 500); + throw new Exception('Cache is not available', 500, Exception::CACHE_NOT_AVAILABLE); } $output = [ @@ -166,7 +166,7 @@ App::get('/v1/health/time') $diff = ($timestamp - \time()); if ($diff > $gap || $diff < ($gap * -1)) { - throw new Exception('Server time gaps detected'); + throw new Exception('Server time gaps detected', 500, Exception::TIME_GAPS_DETECTED); } $output = [ @@ -294,11 +294,11 @@ App::get('/v1/health/storage/local') $device = new Local($volume); if (!\is_readable($device->getRoot())) { - throw new Exception('Device '.$key.' dir is not readable'); + throw new Exception('Device '.$key.' dir is not readable', 500, Exception::STORAGE_NOT_READABLE); } if (!\is_writable($device->getRoot())) { - throw new Exception('Device '.$key.' dir is not writable'); + throw new Exception('Device '.$key.' dir is not writable', 500, Exception::STORAGE_NOT_WRITABLE); } } @@ -341,7 +341,7 @@ App::get('/v1/health/anti-virus') $output['version'] = @$antivirus->version(); $output['status'] = (@$antivirus->ping()) ? 'pass' : 'fail'; } catch( \Exception $e) { - throw new Exception('Antivirus is not available', 500); + throw new Exception('Antivirus is not available', 500, Exception::ANTIVIRUS_NOT_AVAILABLE); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index ccab54662b..5bad4ad3ae 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -75,6 +75,7 @@ class Exception extends \Exception const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Storage */ + const STORAGE_ERROR = 'storage_error'; const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; const STORAGE_FILE_DELETION_FAILED = 'storage_file_deletion_failed'; @@ -155,9 +156,15 @@ class Exception extends \Exception const INVALID_READ_PERMISSIONS = 'invalid_read_permissions'; const INVALID_WRITE_PERMISSIONS = 'invalid_write_permissions'; const UNAUTHORIZED_SCOPE = 'unauthorized_scope'; - const STORAGE_ERROR = 'storage_error'; const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; const SMTP_DISABLED = 'smtp_disabled'; + const DATABASE_NOT_AVAILABLE = 'database_not_available'; + const CACHE_NOT_AVAILABLE = 'cache_not_available'; + const TIME_GAPS_DETECTED = 'time_gaps_detected'; + const STORAGE_NOT_READABLE = 'storage_not_readable'; + const STORAGE_NOT_WRITABLE = 'storage_not_writable'; + const ANTIVIRUS_NOT_AVAILABLE = 'antivirus_not_available'; + private $errorCode = ''; From adf103730b45bf1e7ab6e38787733187ed99c64d Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 6 Feb 2022 21:27:13 +0400 Subject: [PATCH 51/95] feat: update error codes in the health API --- app/config/errors.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index c92e001924..7de4ac21db 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -49,6 +49,36 @@ return [ 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project ', 'statusCode' => 503, ], + Exception::DATABASE_NOT_AVAILABLE => [ + 'name' => Exception::DATABASE_NOT_AVAILABLE, + 'description' => 'Database is not available. Please contact your project owner.', + 'statusCode' => 503, + ], + Exception::CACHE_NOT_AVAILABLE => [ + 'name' => Exception::CACHE_NOT_AVAILABLE, + 'description' => 'Cache is not available. Please contact your project owner.', + 'statusCode' => 503, + ], + Exception::TIME_GAPS_DETECTED => [ + 'name' => Exception::TIME_GAPS_DETECTED, + 'description' => 'Time gaps detected. Please contact your project owner.', + 'statusCode' => 503, + ], + Exception::STORAGE_NOT_READABLE => [ + 'name' => Exception::STORAGE_NOT_READABLE, + 'description' => 'Storage is not readable. Please contact your project owner.', + 'statusCode' => 503, + ], + Exception::STORAGE_NOT_WRITABLE => [ + 'name' => Exception::STORAGE_NOT_WRITABLE, + 'description' => 'Storage is not writable. Please contact your project owner.', + 'statusCode' => 503, + ], + Exception::ANTIVIRUS_NOT_AVAILABLE => [ + 'name' => Exception::ANTIVIRUS_NOT_AVAILABLE, + 'description' => 'Antivirus is not available. Please contact your project owner.', + 'statusCode' => 503, + ], /** Project Errors */ Exception::PROJECT_NOT_FOUND => [ From 49bfb25df69a2bd90372dd6b3fb4fb215ac91840 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:36:15 +0400 Subject: [PATCH 52/95] feat: use general server errors in accounts API --- app/config/errors.php | 15 --------------- app/controllers/api/account.php | 8 ++++---- src/Appwrite/Extend/Exception.php | 6 +++--- 3 files changed, 7 insertions(+), 22 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 7de4ac21db..f30a2cd792 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -178,11 +178,6 @@ return [ 'description' => 'Cannot create anonymous user when a session is active.', 'statusCode' => 401, ], - Exception::USER_CREATION_FAILED => [ - 'name' => Exception::USER_CREATION_FAILED, - 'description' => 'There was an internal server error while creating the user.', - 'statusCode' => 500, - ], Exception::USER_NOT_FOUND => [ 'name' => Exception::USER_NOT_FOUND, 'description' => 'User with the requested ID could not be found.', @@ -225,11 +220,6 @@ return [ 'description' => 'The chosen OAuth provider is unsupported.', 'statusCode' => 501, ], - Exception::OAUTH_INVALID_LOGIN_STATE_PARAMS => [ - 'name' => Exception::OAUTH_INVALID_LOGIN_STATE_PARAMS, - 'description' => 'Failed to parse the login state params from the OAuth provider.', - 'statusCode' => 500, - ], Exception::OAUTH_INVALID_SUCCESS_URL => [ 'name' => Exception::OAUTH_INVALID_SUCCESS_URL, 'description' => 'Invalid URL received for OAuth success redirect.', @@ -240,11 +230,6 @@ return [ 'description' => 'Invalid URL received for OAuth failure redirect.', 'statusCode' => 400, ], - Exception::OAUTH_ACCESS_TOKEN_FAILED => [ - 'name' => Exception::OAUTH_ACCESS_TOKEN_FAILED, - 'description' => 'Failed to obtain access token from the OAuth provider.', - 'statusCode' => 500, - ], Exception::OAUTH_MISSING_USER_ID => [ 'name' => Exception::OAUTH_MISSING_USER_ID, 'description' => 'Failed to obtain user id from the OAuth provider.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 841d6153dd..bd62cb03ef 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -415,7 +415,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') try { $state = \array_merge($defaultState, $oauth2->parseState($state)); } catch (\Exception$exception) { - throw new Exception('Failed to parse login state params as passed from OAuth2 provider', 500, Exception::OAUTH_INVALID_LOGIN_STATE_PARAMS); + throw new Exception('Failed to parse login state params as passed from OAuth2 provider', 500, Exception::GENERAL_SERVER_ERROR); } } else { $state = $defaultState; @@ -437,7 +437,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response->redirect($state['failure'], 301, 0); } - throw new Exception('Failed to obtain access token', 500, Exception::OAUTH_ACCESS_TOKEN_FAILED); + throw new Exception('Failed to obtain access token', 500, Exception::GENERAL_SERVER_ERROR); } $oauth2ID = $oauth2->getUserID($accessToken); @@ -705,7 +705,7 @@ App::post('/v1/account/sessions/magic-url') $user = $dbForProject->updateDocument('users', $user->getId(), $user); if (false === $user) { - throw new Exception('Failed to save user to DB', 500, Exception::USER_CREATION_FAILED); + throw new Exception('Failed to save user to DB', 500, Exception::GENERAL_SERVER_ERROR); } if(empty($url)) { @@ -839,7 +839,7 @@ App::put('/v1/account/sessions/magic-url') $user = $dbForProject->updateDocument('users', $user->getId(), $user); if (false === $user) { - throw new Exception('Failed saving user to DB', 500, Exception::USER_CREATION_FAILED); + throw new Exception('Failed saving user to DB', 500, Exception::GENERAL_SERVER_ERROR); } $audits diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 5bad4ad3ae..895d4107a2 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -28,7 +28,6 @@ class Exception extends \Exception const USER_COUNT_EXCEEDED = 'user_count_exceeded'; const USER_ALREADY_EXISTS = 'user_already_exists'; const USER_BLOCKED = 'user_blocked'; - const USER_CREATION_FAILED = 'user_creation_failed'; const USER_INVALID_TOKEN = 'user_invalid_token'; const USER_NOT_FOUND = 'user_not_found'; const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; @@ -46,10 +45,8 @@ class Exception extends \Exception /** OAuth **/ const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; - const OAUTH_INVALID_LOGIN_STATE_PARAMS = 'oauth_invalid_login_state_params'; const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; - const OAUTH_ACCESS_TOKEN_FAILED = 'oauth_access_token_failed'; const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; /** Teams */ @@ -165,6 +162,9 @@ class Exception extends \Exception const STORAGE_NOT_WRITABLE = 'storage_not_writable'; const ANTIVIRUS_NOT_AVAILABLE = 'antivirus_not_available'; + /** Server Errors */ + const GENERAL_SERVER_ERROR = 'general_server_error'; + private $errorCode = ''; From c1aed2b64b907f4a75dfe6d64bbdb5733dead45d Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:38:14 +0400 Subject: [PATCH 53/95] feat: use general server errors in avatars API --- app/config/errors.php | 15 --------------- app/controllers/api/avatars.php | 10 +++++----- src/Appwrite/Extend/Exception.php | 3 --- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index f30a2cd792..ebd95ab3ab 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -297,21 +297,11 @@ return [ 'description' => 'The request avatar could not be found.', 'statusCode' => 404, ], - Exception::IMAGIC_EXTENSION_MISSING => [ - 'name' => Exception::IMAGIC_EXTENSION_MISSING, - 'description' => 'The Imagic extension could not be found.', - 'statusCode' => 500, - ], Exception::AVATAR_IMAGE_NOT_FOUND => [ 'name' => Exception::AVATAR_IMAGE_NOT_FOUND, 'description' => 'The requested image was not found.', 'statusCode' => 404, ], - Exception::AVATAR_CANNOT_PARSE_IMAGE => [ - 'name' => Exception::AVATAR_CANNOT_PARSE_IMAGE, - 'description' => 'The requested image could not be parsed.', - 'statusCode' => 500, - ], Exception::AVATAR_REMOTE_URL_FAILED => [ 'name' => Exception::AVATAR_REMOTE_URL_FAILED, 'description' => 'The remote URL could not be fetched.', @@ -349,11 +339,6 @@ return [ 'description' => 'The file type is not supported.', 'statusCode' => 400, ], - Exception::STORAGE_FILE_NOT_READABLE => [ - 'name' => Exception::STORAGE_FILE_NOT_READABLE, - 'description' => 'There was an error reading the file from disk.', - 'statusCode' => 500, - ], Exception::STORAGE_INVALID_FILE_SIZE => [ 'name' => Exception::STORAGE_INVALID_FILE_SIZE, 'description' => 'The file size is either not valid or exceeds the maximum allowed size.', diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index c3bd8721ef..af84e4542c 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -33,7 +33,7 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response) } if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); + throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR); } $output = 'png'; @@ -43,7 +43,7 @@ $avatarCallback = function ($type, $code, $width, $height, $quality, $response) $type = 'png'; if (!\is_readable($path)) { - throw new Exception('File not readable in ' . $path, 500, Exception::STORAGE_FILE_NOT_READABLE); + throw new Exception('File not readable in ' . $path, 500, Exception::GENERAL_SERVER_ERROR); } $cache = new Cache(new Filesystem(APP_STORAGE_CACHE . '/app-0')); // Limit file number or size @@ -169,7 +169,7 @@ App::get('/v1/avatars/image') } if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); + throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR); } $fetch = @\file_get_contents($url, false); @@ -181,7 +181,7 @@ App::get('/v1/avatars/image') try { $image = new Image($fetch); } catch (\Exception$exception) { - throw new Exception('Unable to parse image', 500, Exception::AVATAR_CANNOT_PARSE_IMAGE); + throw new Exception('Unable to parse image', 500, Exception::GENERAL_SERVER_ERROR); } $image->crop((int) $width, (int) $height); @@ -238,7 +238,7 @@ App::get('/v1/avatars/favicon') } if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); + throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR); } $curl = \curl_init(); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 895d4107a2..872f836ad7 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -65,9 +65,7 @@ class Exception extends \Exception /** Avatars */ const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; const AVATAR_NOT_FOUND = 'avatar_not_found'; - const IMAGIC_EXTENSION_MISSING = 'imagic_extension_missing'; const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; - const AVATAR_CANNOT_PARSE_IMAGE = 'avatar_cannot_parse_image'; const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; @@ -76,7 +74,6 @@ class Exception extends \Exception const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; const STORAGE_FILE_DELETION_FAILED = 'storage_file_deletion_failed'; - const STORAGE_FILE_NOT_READABLE = 'storage_file_not_readable'; const STORAGE_FILE_EMPTY = 'storage_file_empty'; const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; From 8189dba42c3ea22bac8c899c9e852dedc614eca7 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:49:21 +0400 Subject: [PATCH 54/95] feat: use general server errors in database API --- app/config/errors.php | 5 ----- app/controllers/api/database.php | 2 +- src/Appwrite/Extend/Exception.php | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index ebd95ab3ab..77083d687f 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -407,11 +407,6 @@ return [ 'description' => 'The maximum number of collections has been reached.', 'statusCode' => 400, ], - Exception::COLLECTION_DELETION_FAILED => [ - 'name' => Exception::COLLECTION_DELETION_FAILED, - 'description' => 'Failed to delete the collection from the database.', - 'statusCode' => 500, - ], /** Documents */ Exception::DOCUMENT_NOT_FOUND => [ diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index a2710e9ae4..0375e9a1c7 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -673,7 +673,7 @@ App::delete('/v1/database/collections/:collectionId') } if (!$dbForProject->deleteDocument('collections', $collectionId)) { - throw new Exception('Failed to remove collection from DB', 500, Exception::COLLECTION_DELETION_FAILED); + throw new Exception('Failed to remove collection from DB', 500, Exception::GENERAL_SERVER_ERROR); } $dbForProject->deleteCachedCollection('collection_' . $collectionId); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 872f836ad7..d4c67d50b9 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -96,7 +96,6 @@ class Exception extends \Exception const COLLECTION_NOT_FOUND = 'collection_not_found'; const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; - const COLLECTION_DELETION_FAILED = 'collection_deletion_failed'; /** Documents */ const DOCUMENT_NOT_FOUND = 'document_not_found'; From 1613b3f79ec8cff84ce5f78e24bba2eefdfdc3aa Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:53:26 +0400 Subject: [PATCH 55/95] feat: use general server errors in functions API --- app/config/errors.php | 15 --------------- app/controllers/api/functions.php | 6 +++--- src/Appwrite/Extend/Exception.php | 3 --- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 77083d687f..2112f80b69 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -349,11 +349,6 @@ return [ 'description' => 'The uploaded file is invalid. Please check the file and try again.', 'statusCode' => 403, ], - Exception::STORAGE_FAILED_TO_MOVE_FILE => [ - 'name' => Exception::STORAGE_FAILED_TO_MOVE_FILE, - 'description' => 'Failed to move the uploaded file.', - 'statusCode' => 500, - ], Exception::STORAGE_FAILED_TO_WRITE_FILE => [ 'name' => Exception::STORAGE_FAILED_TO_WRITE_FILE, 'description' => 'Failed to save the uploaded file.', @@ -366,11 +361,6 @@ return [ 'description' => 'The requested function could not be found.', 'statusCode' => 404, ], - Exception::FUNCTION_DELETION_FAILED => [ - 'name' => Exception::FUNCTION_DELETION_FAILED, - 'description' => 'Failed to delete the function from the database.', - 'statusCode' => 500, - ], /** Deployments */ Exception::DEPLOYMENT_NOT_FOUND => [ @@ -378,11 +368,6 @@ return [ 'description' => 'The requested deployment could not be found.', 'statusCode' => 404, ], - Exception::DEPLOYMENT_DELETION_FAILED => [ - 'name' => Exception::DEPLOYMENT_DELETION_FAILED, - 'description' => 'Failed to delete the deployment from the database.', - 'statusCode' => 500, - ], /** Executions */ Exception::EXECUTION_NOT_FOUND => [ diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index ab0a1f5baa..d592ae2670 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -420,7 +420,7 @@ App::delete('/v1/functions/:functionId') } if (!$dbForProject->deleteDocument('functions', $function->getId())) { - throw new Exception('Failed to remove function from DB', 500, Exception::FUNCTION_DELETION_FAILED); + throw new Exception('Failed to remove function from DB', 500, Exception::GENERAL_SERVER_ERROR); } $deletes @@ -496,7 +496,7 @@ App::post('/v1/functions/:functionId/tags') $path = $device->getPath(\uniqid().'.'.\pathinfo($file['name'], PATHINFO_EXTENSION)); if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move' - throw new Exception('Failed moving file', 500, Exception::STORAGE_FAILED_TO_MOVE_FILE); + throw new Exception('Failed moving file', 500, Exception::GENERAL_SERVER_ERROR); } $tagId = $dbForProject->getId(); @@ -654,7 +654,7 @@ App::delete('/v1/functions/:functionId/tags/:tagId') if ($device->delete($tag->getAttribute('path', ''))) { if (!$dbForProject->deleteDocument('tags', $tag->getId())) { - throw new Exception('Failed to remove tag from DB', 500, Exception::DEPLOYMENT_DELETION_FAILED); + throw new Exception('Failed to remove tag from DB', 500, Exception::GENERAL_SERVER_ERROR); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d4c67d50b9..57d35b40ca 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -78,16 +78,13 @@ class Exception extends \Exception const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; const STORAGE_INVALID_FILE = 'storage_invalid_file'; - const STORAGE_FAILED_TO_MOVE_FILE = 'storage_failed_to_move_file'; const STORAGE_FAILED_TO_WRITE_FILE = 'storage_failed_to_write_file'; /** Functions */ const FUNCTION_NOT_FOUND = 'function_not_found'; - const FUNCTION_DELETION_FAILED = 'function_deletion_failed'; /** Deployments */ const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; - const DEPLOYMENT_DELETION_FAILED = 'deployment_deletion_failed'; /** Execution */ const EXECUTION_NOT_FOUND = 'execution_not_found'; From 6e888178316e541f3ab4224b11b25af296e40578 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:55:45 +0400 Subject: [PATCH 56/95] feat: use general server errors in health API --- app/config/errors.php | 197 +++++++++++++----------------- app/controllers/api/health.php | 12 +- src/Appwrite/Extend/Exception.php | 6 - 3 files changed, 89 insertions(+), 126 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 2112f80b69..7178be2174 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -5,272 +5,241 @@ */ use Appwrite\Extend\Exception; -use PhpParser\Node\Expr; return [ /** General Errors */ Exception::UNKNOWN_ORIGIN => [ 'name' => Exception::UNKNOWN_ORIGIN, 'description' => 'The request originated from a non-whitelisted origin. If you trust this origin, please add it as a platform in the Appwrite console.', - 'statusCode' => 403, + 'code' => 403, ], Exception::SERVICE_DISABLED => [ 'name' => Exception::SERVICE_DISABLED, 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', - 'statusCode' => 503, + 'code' => 503, ], Exception::INVALID_READ_PERMISSIONS => [ 'name' => Exception::INVALID_READ_PERMISSIONS, 'description' => 'Invalid format for read permissions. Please check the documentation.', - 'statusCode' => 400, + 'code' => 400, ], Exception::INVALID_WRITE_PERMISSIONS => [ 'name' => Exception::INVALID_WRITE_PERMISSIONS, 'description' => 'Invalid format for write permissions. Please check the documentation.', - 'statusCode' => 400, + 'code' => 400, ], Exception::UNAUTHORIZED_SCOPE => [ 'name' => Exception::UNAUTHORIZED_SCOPE, 'description' => 'The current user or API key does not have the required scopes to access the requested resource.', - 'statusCode' => 401, + 'code' => 401, ], Exception::STORAGE_ERROR => [ 'name' => Exception::STORAGE_ERROR, 'description' => 'Storage error', - 'statusCode' => 500, + 'code' => 500, ], Exception::RATE_LIMIT_EXCEEDED => [ 'name' => Exception::RATE_LIMIT_EXCEEDED, 'description' => 'Rate limit for the current endpoint has been exceeded. Please try again after some time.', - 'statusCode' => 429, + 'code' => 429, ], Exception::SMTP_DISABLED => [ 'name' => Exception::SMTP_DISABLED, 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project ', - 'statusCode' => 503, - ], - Exception::DATABASE_NOT_AVAILABLE => [ - 'name' => Exception::DATABASE_NOT_AVAILABLE, - 'description' => 'Database is not available. Please contact your project owner.', - 'statusCode' => 503, - ], - Exception::CACHE_NOT_AVAILABLE => [ - 'name' => Exception::CACHE_NOT_AVAILABLE, - 'description' => 'Cache is not available. Please contact your project owner.', - 'statusCode' => 503, - ], - Exception::TIME_GAPS_DETECTED => [ - 'name' => Exception::TIME_GAPS_DETECTED, - 'description' => 'Time gaps detected. Please contact your project owner.', - 'statusCode' => 503, - ], - Exception::STORAGE_NOT_READABLE => [ - 'name' => Exception::STORAGE_NOT_READABLE, - 'description' => 'Storage is not readable. Please contact your project owner.', - 'statusCode' => 503, - ], - Exception::STORAGE_NOT_WRITABLE => [ - 'name' => Exception::STORAGE_NOT_WRITABLE, - 'description' => 'Storage is not writable. Please contact your project owner.', - 'statusCode' => 503, - ], - Exception::ANTIVIRUS_NOT_AVAILABLE => [ - 'name' => Exception::ANTIVIRUS_NOT_AVAILABLE, - 'description' => 'Antivirus is not available. Please contact your project owner.', - 'statusCode' => 503, + 'code' => 503, ], /** Project Errors */ Exception::PROJECT_NOT_FOUND => [ 'name' => Exception::PROJECT_NOT_FOUND, 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'statusCode' => 404, + 'code' => 404, ], Exception::PROJECT_UNKNOWN => [ 'name' => Exception::PROJECT_UNKNOWN, 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'statusCode' => 400, + 'code' => 400, ], Exception::WEBHOOK_NOT_FOUND => [ 'name' => Exception::WEBHOOK_NOT_FOUND, 'description' => 'The requested webhook could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::KEY_NOT_FOUND => [ 'name' => Exception::KEY_NOT_FOUND, 'description' => 'The requested key could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::PLATFORM_NOT_FOUND => [ 'name' => Exception::PLATFORM_NOT_FOUND, 'description' => 'The requested platform could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::DOMAIN_NOT_FOUND => [ 'name' => Exception::DOMAIN_NOT_FOUND, 'description' => 'The requested domain could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::DOMAIN_ALREADY_EXISTS => [ 'name' => Exception::DOMAIN_ALREADY_EXISTS, 'description' => 'The requested domain already exists.', - 'statusCode' => 409, + 'code' => 409, ], Exception::DOMAIN_UNREACHABLE => [ 'name' => Exception::DOMAIN_UNREACHABLE, 'description' => 'The requested domain is not reachable.', - 'statusCode' => 503, + 'code' => 503, ], Exception::DOMAIN_VERIFICATION_FAILED => [ 'name' => Exception::DOMAIN_VERIFICATION_FAILED, 'description' => 'The requested domain verification failed.', - 'statusCode' => 503, + 'code' => 503, ], /** User Errors */ Exception::USER_COUNT_EXCEEDED => [ 'name' => Exception::USER_COUNT_EXCEEDED, 'description' => 'The current project has exceeded the maximum number of users. Please check your user limit in the Appwrite console.', - 'statusCode' => 501, + 'code' => 501, ], Exception::USER_EMAIL_NOT_WHITELISTED => [ 'name' => Exception::USER_EMAIL_NOT_WHITELISTED, 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_PASSWORD_RESET_REQUIRED => [ 'name' => Exception::USER_PASSWORD_RESET_REQUIRED, 'description' => 'The current user requires a password reset.', - 'statusCode' => 412, + 'code' => 412, ], Exception::USER_IP_NOT_WHITELISTED => [ 'name' => Exception::USER_IP_NOT_WHITELISTED, 'description' => 'The user\'s IP address is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_IPS environment variable of your Appwrite server.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_INVALID_CREDENTIALS => [ 'name' => Exception::USER_INVALID_CREDENTIALS, 'description' => 'Invalid credentials. Please check the email and password.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_ALREADY_EXISTS => [ 'name' => Exception::USER_ALREADY_EXISTS, 'description' => 'A user with the same email ID already exists in your project.', - 'statusCode' => 409, + 'code' => 409, ], Exception::USER_INVALID_TOKEN => [ 'name' => Exception::USER_INVALID_TOKEN, 'description' => 'Invalid token.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_BLOCKED => [ 'name' => Exception::USER_BLOCKED, 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED => [ 'name' => Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'description' => 'Anonymous users cannot be created for console project.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_SESSION_ALREADY_EXISTS => [ 'name' => Exception::USER_SESSION_ALREADY_EXISTS, 'description' => 'Cannot create anonymous user when a session is active.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_NOT_FOUND => [ 'name' => Exception::USER_NOT_FOUND, 'description' => 'User with the requested ID could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::USER_EMAIL_ALREADY_EXISTS => [ 'name' => Exception::USER_EMAIL_ALREADY_EXISTS, 'description' => 'Another user with the same email already exists in the current project.', - 'statusCode' => 409, + 'code' => 409, ], Exception::USER_PASSWORD_MISMATCH => [ 'name' => Exception::USER_PASSWORD_MISMATCH, 'description' => 'Passwords do not match. Please recheck.', - 'statusCode' => 400, + 'code' => 400, ], Exception::USER_SESSION_NOT_FOUND => [ 'name' => Exception::USER_SESSION_NOT_FOUND, 'description' => 'The current user session could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::USER_UNAUTHORIZED => [ 'name' => Exception::USER_UNAUTHORIZED, 'description' => 'The current user is not authorized to perform the requested action.', - 'statusCode' => 401, + 'code' => 401, ], Exception::USER_AUTH_METHOD_UNSUPPORTED => [ 'name' => Exception::USER_AUTH_METHOD_UNSUPPORTED, 'description' => 'The requested authentication method is either disabled or unsupported.', - 'statusCode' => 501, + 'code' => 501, ], /** OAuth Errors */ Exception::OAUTH_PROVIDER_DISABLED => [ 'name' => Exception::OAUTH_PROVIDER_DISABLED, 'description' => 'The chosen OAuth provider is disabled. Please contact your project administrator for more information.', - 'statusCode' => 412, + 'code' => 412, ], Exception::OAUTH_PROVIDER_UNSUPPORTED => [ 'name' => Exception::OAUTH_PROVIDER_UNSUPPORTED, 'description' => 'The chosen OAuth provider is unsupported.', - 'statusCode' => 501, + 'code' => 501, ], Exception::OAUTH_INVALID_SUCCESS_URL => [ 'name' => Exception::OAUTH_INVALID_SUCCESS_URL, 'description' => 'Invalid URL received for OAuth success redirect.', - 'statusCode' => 400, + 'code' => 400, ], Exception::OAUTH_INVALID_FAILURE_URL => [ 'name' => Exception::OAUTH_INVALID_FAILURE_URL, 'description' => 'Invalid URL received for OAuth failure redirect.', - 'statusCode' => 400, + 'code' => 400, ], Exception::OAUTH_MISSING_USER_ID => [ 'name' => Exception::OAUTH_MISSING_USER_ID, 'description' => 'Failed to obtain user id from the OAuth provider.', - 'statusCode' => 400, + 'code' => 400, ], /** Teams */ Exception::TEAM_NOT_FOUND => [ 'name' => Exception::TEAM_NOT_FOUND, 'description' => 'Team with the requested ID could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::TEAM_DELETION_FAILED => [ 'name' => Exception::TEAM_DELETION_FAILED, 'description' => 'Failed to delete team from the database.', - 'statusCode' => 500, + 'code' => 500, ], Exception::TEAM_INVITE_ALREADY_EXISTS => [ 'name' => Exception::TEAM_INVITE_ALREADY_EXISTS, 'description' => 'The current user already has an invitation to this team.', - 'statusCode' => 409, + 'code' => 409, ], Exception::TEAM_INVITE_NOT_FOUND => [ 'name' => Exception::TEAM_INVITE_NOT_FOUND, 'description' => 'The requested invitation could not be found.', - 'statusCode' => 409, + 'code' => 409, ], Exception::TEAM_INVALID_SECRET => [ 'name' => Exception::TEAM_INVALID_SECRET, 'description' => 'The team invitation secret is invalid.', - 'statusCode' => 401, + 'code' => 401, ], Exception::TEAM_MEMBERSHIP_MISMATCH => [ 'name' => Exception::TEAM_MEMBERSHIP_MISMATCH, 'description' => 'The membership ID does not belong to the team ID.', - 'statusCode' => 404, + 'code' => 404, ], Exception::TEAM_INVITE_MISMATCH => [ 'name' => Exception::TEAM_INVITE_MISMATCH, 'description' => 'The invite does not belong to the current user.', - 'statusCode' => 401, + 'code' => 401, ], @@ -278,211 +247,211 @@ return [ Exception::MEMBERSHIP_NOT_FOUND => [ 'name' => Exception::MEMBERSHIP_NOT_FOUND, 'description' => 'Membership with the requested ID could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::MEMBERSHIP_DELETION_FAILED => [ 'name' => Exception::MEMBERSHIP_DELETION_FAILED, 'description' => 'Failed to delete membership from the database.', - 'statusCode' => 500, + 'code' => 500, ], /** Avatars */ Exception::AVATAR_SET_NOT_FOUND => [ 'name' => Exception::AVATAR_SET_NOT_FOUND, 'description' => 'The requested avatar set could not be found.', - 'statusCode' => 404 + 'code' => 404 ], Exception::AVATAR_NOT_FOUND => [ 'name' => Exception::AVATAR_NOT_FOUND, 'description' => 'The request avatar could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::AVATAR_IMAGE_NOT_FOUND => [ 'name' => Exception::AVATAR_IMAGE_NOT_FOUND, 'description' => 'The requested image was not found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::AVATAR_REMOTE_URL_FAILED => [ 'name' => Exception::AVATAR_REMOTE_URL_FAILED, 'description' => 'The remote URL could not be fetched.', - 'statusCode' => 404, + 'code' => 404, ], Exception::AVATAR_ICON_NOT_FOUND => [ 'name' => Exception::AVATAR_ICON_NOT_FOUND, 'description' => 'The requested favicon could not be found.', - 'statusCode' => 404, + 'code' => 404, ], /** Storage */ Exception::STORAGE_FILE_NOT_FOUND => [ 'name' => Exception::STORAGE_FILE_NOT_FOUND, 'description' => 'The requested file could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::STORAGE_DEVICE_NOT_FOUND => [ 'name' => Exception::STORAGE_DEVICE_NOT_FOUND, 'description' => 'The requested storage device could not be found.', - 'statusCode' => 400, + 'code' => 400, ], Exception::STORAGE_FILE_DELETION_FAILED => [ 'name' => Exception::STORAGE_FILE_DELETION_FAILED, 'description' => 'There was an issue deleting the file from the database.', - 'statusCode' => 500, + 'code' => 500, ], Exception::STORAGE_FILE_EMPTY => [ 'name' => Exception::STORAGE_FILE_EMPTY, 'description' => 'Empty file passed to the endpoint.', - 'statusCode' => 400, + 'code' => 400, ], Exception::STORAGE_FILE_TYPE_UNSUPPORTED => [ 'name' => Exception::STORAGE_FILE_TYPE_UNSUPPORTED, 'description' => 'The file type is not supported.', - 'statusCode' => 400, + 'code' => 400, ], Exception::STORAGE_INVALID_FILE_SIZE => [ 'name' => Exception::STORAGE_INVALID_FILE_SIZE, 'description' => 'The file size is either not valid or exceeds the maximum allowed size.', - 'statusCode' => 400, + 'code' => 400, ], Exception::STORAGE_INVALID_FILE => [ 'name' => Exception::STORAGE_INVALID_FILE, 'description' => 'The uploaded file is invalid. Please check the file and try again.', - 'statusCode' => 403, + 'code' => 403, ], Exception::STORAGE_FAILED_TO_WRITE_FILE => [ 'name' => Exception::STORAGE_FAILED_TO_WRITE_FILE, 'description' => 'Failed to save the uploaded file.', - 'statusCode' => 500, + 'code' => 500, ], /** Functions */ Exception::FUNCTION_NOT_FOUND => [ 'name' => Exception::FUNCTION_NOT_FOUND, 'description' => 'The requested function could not be found.', - 'statusCode' => 404, + 'code' => 404, ], /** Deployments */ Exception::DEPLOYMENT_NOT_FOUND => [ 'name' => Exception::DEPLOYMENT_NOT_FOUND, 'description' => 'The requested deployment could not be found.', - 'statusCode' => 404, + 'code' => 404, ], /** Executions */ Exception::EXECUTION_NOT_FOUND => [ 'name' => Exception::EXECUTION_NOT_FOUND, 'description' => 'The requested execution could not be found.', - 'statusCode' => 404, + 'code' => 404, ], /** Collections */ Exception::COLLECTION_NOT_FOUND => [ 'name' => Exception::COLLECTION_NOT_FOUND, 'description' => 'The requested collection could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::COLLECTION_ALREADY_EXISTS => [ 'name' => Exception::COLLECTION_ALREADY_EXISTS, 'description' => 'The collection already exists.', - 'statusCode' => 400, + 'code' => 400, ], Exception::COLLECTION_LIMIT_EXCEEDED => [ 'name' => Exception::COLLECTION_LIMIT_EXCEEDED, 'description' => 'The maximum number of collections has been reached.', - 'statusCode' => 400, + 'code' => 400, ], /** Documents */ Exception::DOCUMENT_NOT_FOUND => [ 'name' => Exception::DOCUMENT_NOT_FOUND, 'description' => 'The requested document could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::DOCUMENT_INVALID_STRUCTURE => [ 'name' => Exception::DOCUMENT_INVALID_STRUCTURE, 'description' => 'The document structure is invalid.', - 'statusCode' => 400, + 'code' => 400, ], Exception::DOCUMENT_MISSING_PAYLOAD => [ 'name' => Exception::DOCUMENT_MISSING_PAYLOAD, 'description' => 'The document payload is missing.', - 'statusCode' => 400, + 'code' => 400, ], Exception::DOCUMENT_ALREADY_EXISTS => [ 'name' => Exception::DOCUMENT_ALREADY_EXISTS, 'description' => 'The document already exists.', - 'statusCode' => 400, + 'code' => 400, ], /** Attributes */ Exception::ATTRIBUTE_NOT_FOUND => [ 'name' => Exception::ATTRIBUTE_NOT_FOUND, 'description' => 'The requested attribute could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::ATTRIBUTE_UNKNOWN => [ 'name' => Exception::ATTRIBUTE_UNKNOWN, 'description' => 'The requested attribute could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::ATTRIBUTE_NOT_AVAILABLE => [ 'name' => Exception::ATTRIBUTE_NOT_AVAILABLE, 'description' => 'The requested attribute is not available.', - 'statusCode' => 404, + 'code' => 404, ], Exception::ATTRIBUTE_FORMAT_UNSUPPORTED => [ 'name' => Exception::ATTRIBUTE_FORMAT_UNSUPPORTED, 'description' => 'The requested attribute format is not supported.', - 'statusCode' => 400, + 'code' => 400, ], Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED => [ 'name' => Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'description' => 'The requested attribute default value is not supported.', - 'statusCode' => 400, + 'code' => 400, ], Exception::ATTRIBUTE_ALREADY_EXISTS => [ 'name' => Exception::ATTRIBUTE_ALREADY_EXISTS, 'description' => 'The attribute already exists.', - 'statusCode' => 400, + 'code' => 400, ], Exception::ATTRIBUTE_LIMIT_EXCEEDED => [ 'name' => Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'description' => 'The maximum number of attributes has been reached.', - 'statusCode' => 400, + 'code' => 400, ], Exception::ATTRIBUTE_VALUE_INVALID => [ 'name' => Exception::ATTRIBUTE_VALUE_INVALID, 'description' => 'The attribute value is invalid.', - 'statusCode' => 400, + 'code' => 400, ], /** Indexes */ Exception::INDEX_NOT_FOUND => [ 'name' => Exception::INDEX_NOT_FOUND, 'description' => 'The requested index could not be found.', - 'statusCode' => 404, + 'code' => 404, ], Exception::INDEX_LIMIT_EXCEEDED => [ 'name' => Exception::INDEX_LIMIT_EXCEEDED, 'description' => 'The maximum number of indexes has been reached.', - 'statusCode' => 400, + 'code' => 400, ], Exception::INDEX_ALREADY_EXISTS => [ 'name' => Exception::INDEX_ALREADY_EXISTS, 'description' => 'The index already exists.', - 'statusCode' => 400, + 'code' => 400, ], /** Query */ Exception::QUERY_LIMIT_EXCEEDED => [ 'name' => Exception::QUERY_LIMIT_EXCEEDED, 'description' => 'The maximum number of results has been reached.', - 'statusCode' => 400, + 'code' => 400, ], Exception::QUERY_INVALID => [ 'name' => Exception::QUERY_INVALID, 'description' => 'The query is invalid.', - 'statusCode' => 400, + 'code' => 400, ], ]; \ No newline at end of file diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index fdc8101f58..5508d56030 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -75,7 +75,7 @@ App::get('/v1/health/db') $statement->execute(); } catch (Exception $_e) { - throw new Exception('Database is not available', 500, Exception::DATABASE_NOT_AVAILABLE); + throw new Exception('Database is not available', 500, Exception::GENERAL_SERVER_ERROR); } $output = [ @@ -109,7 +109,7 @@ App::get('/v1/health/cache') $redis = $utopia->getResource('cache'); if (!$redis->ping(true)) { - throw new Exception('Cache is not available', 500, Exception::CACHE_NOT_AVAILABLE); + throw new Exception('Cache is not available', 500, Exception::GENERAL_SERVER_ERROR); } $output = [ @@ -166,7 +166,7 @@ App::get('/v1/health/time') $diff = ($timestamp - \time()); if ($diff > $gap || $diff < ($gap * -1)) { - throw new Exception('Server time gaps detected', 500, Exception::TIME_GAPS_DETECTED); + throw new Exception('Server time gaps detected', 500, Exception::GENERAL_SERVER_ERROR); } $output = [ @@ -294,11 +294,11 @@ App::get('/v1/health/storage/local') $device = new Local($volume); if (!\is_readable($device->getRoot())) { - throw new Exception('Device '.$key.' dir is not readable', 500, Exception::STORAGE_NOT_READABLE); + throw new Exception('Device '.$key.' dir is not readable', 500, Exception::GENERAL_SERVER_ERROR); } if (!\is_writable($device->getRoot())) { - throw new Exception('Device '.$key.' dir is not writable', 500, Exception::STORAGE_NOT_WRITABLE); + throw new Exception('Device '.$key.' dir is not writable', 500, Exception::GENERAL_SERVER_ERROR); } } @@ -341,7 +341,7 @@ App::get('/v1/health/anti-virus') $output['version'] = @$antivirus->version(); $output['status'] = (@$antivirus->ping()) ? 'pass' : 'fail'; } catch( \Exception $e) { - throw new Exception('Antivirus is not available', 500, Exception::ANTIVIRUS_NOT_AVAILABLE); + throw new Exception('Antivirus is not available', 500, Exception::GENERAL_SERVER_ERROR); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 57d35b40ca..906b24206a 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -148,12 +148,6 @@ class Exception extends \Exception const UNAUTHORIZED_SCOPE = 'unauthorized_scope'; const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; const SMTP_DISABLED = 'smtp_disabled'; - const DATABASE_NOT_AVAILABLE = 'database_not_available'; - const CACHE_NOT_AVAILABLE = 'cache_not_available'; - const TIME_GAPS_DETECTED = 'time_gaps_detected'; - const STORAGE_NOT_READABLE = 'storage_not_readable'; - const STORAGE_NOT_WRITABLE = 'storage_not_writable'; - const ANTIVIRUS_NOT_AVAILABLE = 'antivirus_not_available'; /** Server Errors */ const GENERAL_SERVER_ERROR = 'general_server_error'; From 3b420fdeed3a710e0b13d96e4b035efe1ea304a8 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:56:48 +0400 Subject: [PATCH 57/95] feat: use general server errors in projects API --- app/controllers/api/projects.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 893300d9b2..4fd26873cd 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -557,11 +557,11 @@ App::delete('/v1/projects/:projectId') ; if (!$dbForConsole->deleteDocument('teams', $project->getAttribute('teamId', null))) { - throw new Exception('Failed to remove project team from DB', 500, Exception::COLLECTION_DELETION_FAILED); + throw new Exception('Failed to remove project team from DB', 500, Exception::GENERAL_SERVER_ERROR); } if (!$dbForConsole->deleteDocument('projects', $projectId)) { - throw new Exception('Failed to remove project from DB', 500, Exception::COLLECTION_DELETION_FAILED); + throw new Exception('Failed to remove project from DB', 500, Exception::GENERAL_SERVER_ERROR); } $response->noContent(); From 3cdccf00242c9954446fc6ce853c1ed397514a5e Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 00:58:40 +0400 Subject: [PATCH 58/95] feat: use general server errors in storage API --- app/config/errors.php | 10 ---------- app/controllers/api/storage.php | 8 ++++---- src/Appwrite/Extend/Exception.php | 2 -- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 7178be2174..05265dd20f 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -293,11 +293,6 @@ return [ 'description' => 'The requested storage device could not be found.', 'code' => 400, ], - Exception::STORAGE_FILE_DELETION_FAILED => [ - 'name' => Exception::STORAGE_FILE_DELETION_FAILED, - 'description' => 'There was an issue deleting the file from the database.', - 'code' => 500, - ], Exception::STORAGE_FILE_EMPTY => [ 'name' => Exception::STORAGE_FILE_EMPTY, 'description' => 'Empty file passed to the endpoint.', @@ -318,11 +313,6 @@ return [ 'description' => 'The uploaded file is invalid. Please check the file and try again.', 'code' => 403, ], - Exception::STORAGE_FAILED_TO_WRITE_FILE => [ - 'name' => Exception::STORAGE_FAILED_TO_WRITE_FILE, - 'description' => 'Failed to save the uploaded file.', - 'code' => 500, - ], /** Functions */ Exception::FUNCTION_NOT_FOUND => [ diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 0dbadb6aa8..0726fb8719 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -116,7 +116,7 @@ App::post('/v1/storage/files') $path = $device->getPath(\uniqid().'.'.\pathinfo($file['name'], PATHINFO_EXTENSION)); if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move' - throw new Exception('Failed moving file', 500, Exception::STORAGE_FAILED_TO_MOVE_FILE); + throw new Exception('Failed moving file', 500, Exception::GENERAL_SERVER_ERROR); } $mimeType = $device->getFileMimeType($path); // Get mime-type before compression and encryption @@ -141,7 +141,7 @@ App::post('/v1/storage/files') $data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag); if (!$device->write($path, $data, $mimeType)) { - throw new Exception('Failed to save file', 500, Exception::STORAGE_FAILED_TO_WRITE_FILE); + throw new Exception('Failed to save file', 500, Exception::GENERAL_SERVER_ERROR); } $sizeActual = $device->getFileSize($path); @@ -304,7 +304,7 @@ App::get('/v1/storage/files/:fileId/preview') $storage = 'files'; if (!\extension_loaded('imagick')) { - throw new Exception('Imagick extension is missing', 500, Exception::IMAGIC_EXTENSION_MISSING); + throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR); } if (!Storage::exists($storage)) { @@ -671,7 +671,7 @@ App::delete('/v1/storage/files/:fileId') if ($device->delete($file->getAttribute('path', ''))) { if (!$dbForProject->deleteDocument('files', $fileId)) { - throw new Exception('Failed to remove file from DB', 500, Exception::STORAGE_FILE_DELETION_FAILED); + throw new Exception('Failed to remove file from DB', 500, Exception::GENERAL_SERVER_ERROR); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 906b24206a..8f0b10ca1a 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -73,12 +73,10 @@ class Exception extends \Exception const STORAGE_ERROR = 'storage_error'; const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; - const STORAGE_FILE_DELETION_FAILED = 'storage_file_deletion_failed'; const STORAGE_FILE_EMPTY = 'storage_file_empty'; const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; const STORAGE_INVALID_FILE = 'storage_invalid_file'; - const STORAGE_FAILED_TO_WRITE_FILE = 'storage_failed_to_write_file'; /** Functions */ const FUNCTION_NOT_FOUND = 'function_not_found'; From 6d343abcb1e4ff7c133fd59908847f64df02a5c4 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:00:06 +0400 Subject: [PATCH 59/95] feat: use general server errors in teams API --- app/config/errors.php | 10 ---------- app/controllers/api/teams.php | 6 +++--- src/Appwrite/Extend/Exception.php | 2 -- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 05265dd20f..403ff9b6d4 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -211,11 +211,6 @@ return [ 'description' => 'Team with the requested ID could not be found.', 'code' => 404, ], - Exception::TEAM_DELETION_FAILED => [ - 'name' => Exception::TEAM_DELETION_FAILED, - 'description' => 'Failed to delete team from the database.', - 'code' => 500, - ], Exception::TEAM_INVITE_ALREADY_EXISTS => [ 'name' => Exception::TEAM_INVITE_ALREADY_EXISTS, 'description' => 'The current user already has an invitation to this team.', @@ -249,11 +244,6 @@ return [ 'description' => 'Membership with the requested ID could not be found.', 'code' => 404, ], - Exception::MEMBERSHIP_DELETION_FAILED => [ - 'name' => Exception::MEMBERSHIP_DELETION_FAILED, - 'description' => 'Failed to delete membership from the database.', - 'code' => 500, - ], /** Avatars */ Exception::AVATAR_SET_NOT_FOUND => [ diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 9f428ad574..908a8a195b 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -232,12 +232,12 @@ App::delete('/v1/teams/:teamId') // TODO delete all members individually from the user object foreach ($memberships as $membership) { if (!$dbForProject->deleteDocument('memberships', $membership->getId())) { - throw new Exception('Failed to remove membership for team from DB', 500, Exception::MEMBERSHIP_DELETION_FAILED); + throw new Exception('Failed to remove membership for team from DB', 500, Exception::GENERAL_SERVER_ERROR); } } if (!$dbForProject->deleteDocument('teams', $teamId)) { - throw new Exception('Failed to remove team from DB', 500, Exception::TEAM_DELETION_FAILED); + throw new Exception('Failed to remove team from DB', 500, Exception::GENERAL_SERVER_ERROR); } $deletes @@ -767,7 +767,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') } catch (AuthorizationException $exception) { throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } catch (\Exception $exception) { - throw new Exception('Failed to remove membership from DB', 500, Exception::MEMBERSHIP_DELETION_FAILED); + throw new Exception('Failed to remove membership from DB', 500, Exception::GENERAL_SERVER_ERROR); } $memberships = $user->getAttribute('memberships', []); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 8f0b10ca1a..0b85b12edd 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -51,7 +51,6 @@ class Exception extends \Exception /** Teams */ const TEAM_NOT_FOUND = 'team_not_found'; - const TEAM_DELETION_FAILED = 'team_deletion_failed'; const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; const TEAM_INVALID_SECRET = 'team_invalid_secret'; @@ -60,7 +59,6 @@ class Exception extends \Exception /** Membership */ const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; - const MEMBERSHIP_DELETION_FAILED = 'membership_deletion_failed'; /** Avatars */ const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; From f197bbf564716f6b15f58960363bdc3a92de5ef6 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:01:23 +0400 Subject: [PATCH 60/95] feat: use general server errors in shared API controller --- 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 f2abfc90f3..470cc348e3 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -179,7 +179,7 @@ App::init(function ($utopia, $request, $project) { break; default: - throw new Exception('Unsupported authentication route', Exception::USER_AUTH_METHOD_UNSUPPORTED); + throw new Exception('Unsupported authentication route', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED); break; } From 30c5d3c264c3ecc913c85ad696fdaea67b583094 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:27:16 +0400 Subject: [PATCH 61/95] feat: use general server errors in general API controller --- app/config/errors.php | 25 +++++++++++++++---------- app/controllers/api/account.php | 6 +++--- app/controllers/api/projects.php | 2 +- app/controllers/api/teams.php | 2 +- app/controllers/general.php | 10 +++++----- app/controllers/shared/api.php | 2 +- app/controllers/web/console.php | 5 +++-- app/init.php | 5 +++-- src/Appwrite/Extend/Exception.php | 26 ++++++++++++-------------- 9 files changed, 44 insertions(+), 39 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 403ff9b6d4..ac5bc34ee4 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -8,13 +8,13 @@ use Appwrite\Extend\Exception; return [ /** General Errors */ - Exception::UNKNOWN_ORIGIN => [ - 'name' => Exception::UNKNOWN_ORIGIN, + Exception::GENERAL_UNKNOWN_ORIGIN => [ + 'name' => Exception::GENERAL_UNKNOWN_ORIGIN, 'description' => 'The request originated from a non-whitelisted origin. If you trust this origin, please add it as a platform in the Appwrite console.', 'code' => 403, ], - Exception::SERVICE_DISABLED => [ - 'name' => Exception::SERVICE_DISABLED, + Exception::GENERAL_SERVICE_DISABLED => [ + 'name' => Exception::GENERAL_SERVICE_DISABLED, 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', 'code' => 503, ], @@ -28,8 +28,8 @@ return [ 'description' => 'Invalid format for write permissions. Please check the documentation.', 'code' => 400, ], - Exception::UNAUTHORIZED_SCOPE => [ - 'name' => Exception::UNAUTHORIZED_SCOPE, + Exception::GENERAL_UNAUTHORIZED_SCOPE => [ + 'name' => Exception::GENERAL_UNAUTHORIZED_SCOPE, 'description' => 'The current user or API key does not have the required scopes to access the requested resource.', 'code' => 401, ], @@ -38,13 +38,13 @@ return [ 'description' => 'Storage error', 'code' => 500, ], - Exception::RATE_LIMIT_EXCEEDED => [ - 'name' => Exception::RATE_LIMIT_EXCEEDED, + Exception::GENERAL_RATE_LIMIT_EXCEEDED => [ + 'name' => Exception::GENERAL_RATE_LIMIT_EXCEEDED, 'description' => 'Rate limit for the current endpoint has been exceeded. Please try again after some time.', 'code' => 429, ], - Exception::SMTP_DISABLED => [ - 'name' => Exception::SMTP_DISABLED, + Exception::GENERAL_SMTP_DISABLED => [ + 'name' => Exception::GENERAL_SMTP_DISABLED, 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project ', 'code' => 503, ], @@ -107,6 +107,11 @@ return [ 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', 'code' => 401, ], + Exception::USER_JWT_INVALID => [ + 'name' => Exception::USER_JWT_INVALID, + 'description' => 'The JWT token is invalid. Please check the value of the X-Appwrite-JWT header to ensure the correct token is being used.', + 'code' => 401, + ], Exception::USER_PASSWORD_RESET_REQUIRED => [ 'name' => Exception::USER_PASSWORD_RESET_REQUIRED, 'description' => 'The current user requires a password reset.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index bd62cb03ef..c465df9537 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -637,7 +637,7 @@ App::post('/v1/account/sessions/magic-url') /** @var Appwrite\Event\Event $mails */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -1764,7 +1764,7 @@ App::post('/v1/account/recovery') /** @var Appwrite\Stats\Stats $usage */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); } $roles = Authorization::getRoles(); @@ -1957,7 +1957,7 @@ App::post('/v1/account/verification') /** @var Appwrite\Stats\Stats $usage */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); } $roles = Authorization::getRoles(); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 4fd26873cd..df6ab569f0 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -29,7 +29,7 @@ App::init(function ($project) { /** @var Utopia\Database\Document $project */ if ($project->getId() !== 'console') { - throw new Exception('Access to this API is forbidden.', 401, Exception::ACCESS_FORBIDDEN); + throw new Exception('Access to this API is forbidden.', 401, Exception::GENERAL_ACCESS_FORBIDDEN); } }, ['project'], 'projects'); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 908a8a195b..c0180b9d3f 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -287,7 +287,7 @@ App::post('/v1/teams/:teamId/memberships') /** @var Appwrite\Event\Event $mails */ if(empty(App::getEnv('_APP_SMTP_HOST'))) { - throw new Exception('SMTP Disabled', 503, Exception::SMTP_DISABLED); + throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); } $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); diff --git a/app/controllers/general.php b/app/controllers/general.php index dba5caed94..ee7485fe83 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -214,7 +214,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons && \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE]) && $route->getLabel('origin', false) !== '*' && empty($request->getHeader('x-appwrite-key', ''))) { - throw new Exception($originValidator->getDescription(), 403, Exception::UNKNOWN_ORIGIN); + throw new Exception($originValidator->getDescription(), 403, Exception::GENERAL_UNKNOWN_ORIGIN); } /* @@ -283,7 +283,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons if(array_key_exists($service, $project->getAttribute('services',[])) && !$project->getAttribute('services',[])[$service] && !Auth::isPrivilegedUser(Authorization::getRoles())) { - throw new Exception('Service is disabled', 503, Exception::SERVICE_DISABLED); + throw new Exception('Service is disabled', 503, Exception::GENERAL_SERVICE_DISABLED); } } @@ -292,7 +292,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } - throw new Exception($user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')', 401, Exception::UNAUTHORIZED_SCOPE); + throw new Exception($user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')', 401, Exception::GENERAL_UNAUTHORIZED_SCOPE); } if (false === $user->getAttribute('status')) { // Account is blocked @@ -530,7 +530,7 @@ App::get('/.well-known/acme-challenge') $absolute = \realpath($base.'/.well-known/acme-challenge/'.$path); if (!$base) { - throw new Exception('Storage error', 500); + throw new Exception('Storage error', 500, Exception::GENERAL_SERVER_ERROR); } if (!$absolute) { @@ -548,7 +548,7 @@ App::get('/.well-known/acme-challenge') $content = @\file_get_contents($absolute); if (!$content) { - throw new Exception('Failed to get contents', 500); + throw new Exception('Failed to get contents', 500, Exception::GENERAL_SERVER_ERROR); } $response->text($content); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 470cc348e3..ce11f870ee 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -81,7 +81,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not disabled && (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key { - throw new Exception('Too many requests', 429, Exception::RATE_LIMIT_EXCEEDED); + throw new Exception('Too many requests', 429, Exception::GENERAL_RATE_LIMIT_EXCEEDED); } } diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index 2a74f7052f..056674967b 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -1,5 +1,6 @@ json(['version' => $version['version']]); } else { - throw new Exception('Failed to check for a newer version', 500); + throw new Exception('Failed to check for a newer version', 500, Exception::GENERAL_SERVER_ERROR); } } catch (\Throwable $th) { - throw new Exception('Failed to check for a newer version', 500); + throw new Exception('Failed to check for a newer version', 500, Exception::GENERAL_SERVER_ERROR); } }); \ No newline at end of file diff --git a/app/init.php b/app/init.php index 7327ab226f..ecfbdce1d2 100644 --- a/app/init.php +++ b/app/init.php @@ -20,6 +20,7 @@ error_reporting(E_ALL); use Appwrite\Extend\PDO; use Ahc\Jwt\JWT; use Ahc\Jwt\JWTException; +use Appwrite\Extend\Exception; use Appwrite\Auth\Auth; use Appwrite\Database\Database as DatabaseOld; use Appwrite\Event\Event; @@ -389,7 +390,7 @@ $register->set('logger', function () { // Register error logger } if(!Logger::hasProvider($providerName)) { - throw new Exception("Logging provider not supported. Logging disabled."); + throw new Exception("Logging provider not supported. Logging disabled.", 500, Exception::GENERAL_SERVER_ERROR); } $classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName); @@ -733,7 +734,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response try { $payload = $jwt->decode($authJWT); } catch (JWTException $error) { - throw new Exception('Failed to verify JWT. '.$error->getMessage(), 401); + throw new Exception('Failed to verify JWT. '.$error->getMessage(), 401, Exception::USER_JWT_INVALID); } $jwtUserId = $payload['userId'] ?? ''; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 0b85b12edd..14177d95d0 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -26,6 +26,7 @@ class Exception extends \Exception /** Users */ const USER_COUNT_EXCEEDED = 'user_count_exceeded'; + const USER_JWT_INVALID = 'user_jwt_invalid'; const USER_ALREADY_EXISTS = 'user_already_exists'; const USER_BLOCKED = 'user_blocked'; const USER_INVALID_TOKEN = 'user_invalid_token'; @@ -135,24 +136,21 @@ class Exception extends \Exception const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; /** General */ - const DEFAULT = 'default'; - const ACCESS_FORBIDDEN = 'access_forbidden'; - const UNKNOWN_ORIGIN = 'unknown_origin'; - const SERVICE_DISABLED = 'service_disabled'; - const INVALID_READ_PERMISSIONS = 'invalid_read_permissions'; - const INVALID_WRITE_PERMISSIONS = 'invalid_write_permissions'; - const UNAUTHORIZED_SCOPE = 'unauthorized_scope'; - const RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; - const SMTP_DISABLED = 'smtp_disabled'; - - /** Server Errors */ - const GENERAL_SERVER_ERROR = 'general_server_error'; - + const GENERAL_DEFAULT = 'general_default'; + const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + const INVALID_READ_PERMISSIONS = 'invalid_read_permissions'; + const INVALID_WRITE_PERMISSIONS = 'invalid_write_permissions'; + const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + const GENERAL_SERVER_ERROR = 'general_server_error'; private $errorCode = ''; - public function __construct(string $message, int $code = 0, string $errorCode = Exception::DEFAULT, \Throwable $previous = null) + public function __construct(string $message, int $code = 0, string $errorCode = Exception::GENERAL_DEFAULT, \Throwable $previous = null) { $this->errorCode = $errorCode; From 42e424b70a59986c3422714ce6c5dbd3a837d9d7 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:33:48 +0400 Subject: [PATCH 62/95] feat: remove unused error --- app/config/errors.php | 10 ---------- app/controllers/api/database.php | 8 ++++---- app/controllers/api/storage.php | 8 ++++---- src/Appwrite/Extend/Exception.php | 10 ++++------ 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index ac5bc34ee4..3510f781e6 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -18,16 +18,6 @@ return [ 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', 'code' => 503, ], - Exception::INVALID_READ_PERMISSIONS => [ - 'name' => Exception::INVALID_READ_PERMISSIONS, - 'description' => 'Invalid format for read permissions. Please check the documentation.', - 'code' => 400, - ], - Exception::INVALID_WRITE_PERMISSIONS => [ - 'name' => Exception::INVALID_WRITE_PERMISSIONS, - 'description' => 'Invalid format for write permissions. Please check the documentation.', - 'code' => 400, - ], Exception::GENERAL_UNAUTHORIZED_SCOPE => [ 'name' => Exception::GENERAL_UNAUTHORIZED_SCOPE, 'description' => 'The current user or API key does not have the required scopes to access the requested resource.', diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 0375e9a1c7..9df02ddaf5 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1628,12 +1628,12 @@ App::post('/v1/database/collections/:collectionId/documents') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($data['$read'] as $read) { if (!Authorization::isRole($read)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } foreach ($data['$write'] as $write) { if (!Authorization::isRole($write)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } } @@ -2013,12 +2013,12 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($data['$read'] as $read) { if (!Authorization::isRole($read)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } foreach ($data['$write'] as $write) { if (!Authorization::isRole($write)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } } diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 0726fb8719..6413fdc696 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -68,12 +68,12 @@ App::post('/v1/storage/files') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } } @@ -602,12 +602,12 @@ App::put('/v1/storage/files/:fileId') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_READ_PERMISSIONS); + throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::INVALID_WRITE_PERMISSIONS); + throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 14177d95d0..83d6d199a1 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -92,10 +92,10 @@ class Exception extends \Exception const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; /** Documents */ - const DOCUMENT_NOT_FOUND = 'document_not_found'; - const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; - const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; - const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; + const DOCUMENT_NOT_FOUND = 'document_not_found'; + const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; + const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; + const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; /** Attribute */ const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; @@ -140,8 +140,6 @@ class Exception extends \Exception const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - const INVALID_READ_PERMISSIONS = 'invalid_read_permissions'; - const INVALID_WRITE_PERMISSIONS = 'invalid_write_permissions'; const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; From a5b706f64b46c87f0e89196f18f6eb18bf330085 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:37:11 +0400 Subject: [PATCH 63/95] feat: adjust formatting --- app/config/errors.php | 5 -- src/Appwrite/Extend/Exception.php | 99 +++++++++++++++---------------- 2 files changed, 49 insertions(+), 55 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 3510f781e6..bfd95622a7 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -23,11 +23,6 @@ return [ 'description' => 'The current user or API key does not have the required scopes to access the requested resource.', 'code' => 401, ], - Exception::STORAGE_ERROR => [ - 'name' => Exception::STORAGE_ERROR, - 'description' => 'Storage error', - 'code' => 500, - ], Exception::GENERAL_RATE_LIMIT_EXCEEDED => [ 'name' => Exception::GENERAL_RATE_LIMIT_EXCEEDED, 'description' => 'Rate limit for the current endpoint has been exceeded. Please try again after some time.', diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 83d6d199a1..7ad933110f 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -44,58 +44,57 @@ class Exception extends \Exception const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; /** OAuth **/ - const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; - const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; - const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; - const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; - const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; + const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; + const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; + const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; + const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; + const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; /** Teams */ - const TEAM_NOT_FOUND = 'team_not_found'; - const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; - const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; - const TEAM_INVALID_SECRET = 'team_invalid_secret'; - const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; - const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; + const TEAM_NOT_FOUND = 'team_not_found'; + const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; + const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; + const TEAM_INVALID_SECRET = 'team_invalid_secret'; + const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; + const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; /** Membership */ - const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; /** Avatars */ - const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; - const AVATAR_NOT_FOUND = 'avatar_not_found'; - const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; - const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; - const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; + const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; + const AVATAR_NOT_FOUND = 'avatar_not_found'; + const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; + const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; + const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Storage */ - const STORAGE_ERROR = 'storage_error'; - const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; - const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; - const STORAGE_FILE_EMPTY = 'storage_file_empty'; - const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; - const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; - const STORAGE_INVALID_FILE = 'storage_invalid_file'; + const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; + const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; + const STORAGE_FILE_EMPTY = 'storage_file_empty'; + const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; + const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; + const STORAGE_INVALID_FILE = 'storage_invalid_file'; /** Functions */ - const FUNCTION_NOT_FOUND = 'function_not_found'; + const FUNCTION_NOT_FOUND = 'function_not_found'; /** Deployments */ - const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; + const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; /** Execution */ - const EXECUTION_NOT_FOUND = 'execution_not_found'; + const EXECUTION_NOT_FOUND = 'execution_not_found'; /** Collections */ - const COLLECTION_NOT_FOUND = 'collection_not_found'; - const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; - const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; + const COLLECTION_NOT_FOUND = 'collection_not_found'; + const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; + const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; /** Documents */ - const DOCUMENT_NOT_FOUND = 'document_not_found'; - const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; - const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; - const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; + const DOCUMENT_NOT_FOUND = 'document_not_found'; + const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; + const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; + const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; /** Attribute */ const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; @@ -108,26 +107,26 @@ class Exception extends \Exception const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; /** Indexes */ - const INDEX_NOT_FOUND = 'index_not_found'; - const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; - const INDEX_ALREADY_EXISTS = 'index_already_exists'; + const INDEX_NOT_FOUND = 'index_not_found'; + const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; + const INDEX_ALREADY_EXISTS = 'index_already_exists'; /** Query limit exceeded */ const QUERY_LIMIT_EXCEEDED = 'query_limit_exceeded'; const QUERY_INVALID = 'query_invalid'; /** Projects */ - const PROJECT_NOT_FOUND = 'project_not_found'; - const PROJECT_UNKNOWN = 'project_unknown'; + const PROJECT_NOT_FOUND = 'project_not_found'; + const PROJECT_UNKNOWN = 'project_unknown'; /** Webhooks */ - const WEBHOOK_NOT_FOUND = 'webhook_not_found'; + const WEBHOOK_NOT_FOUND = 'webhook_not_found'; /** Keys */ - const KEY_NOT_FOUND = 'key_not_found'; + const KEY_NOT_FOUND = 'key_not_found'; /** Platform */ - const PLATFORM_NOT_FOUND = 'platform_not_found'; + const PLATFORM_NOT_FOUND = 'platform_not_found'; /** Domain */ const DOMAIN_NOT_FOUND = 'domain_not_found'; @@ -136,14 +135,14 @@ class Exception extends \Exception const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; /** General */ - const GENERAL_DEFAULT = 'general_default'; - const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; - const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; - const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; - const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; - const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; - const GENERAL_SERVER_ERROR = 'general_server_error'; + const GENERAL_DEFAULT = 'general_default'; + const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + const GENERAL_SERVER_ERROR = 'general_server_error'; private $errorCode = ''; From c46900f06778ba50492e74c3fe2618ba9e27ac82 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:39:33 +0400 Subject: [PATCH 64/95] feat: adjust formatting --- src/Appwrite/Extend/Exception.php | 128 +++++++++++++++--------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 7ad933110f..e4709a31d6 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -44,105 +44,105 @@ class Exception extends \Exception const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; /** OAuth **/ - const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; - const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; - const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; - const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; - const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; + const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; + const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; + const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; + const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; + const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; /** Teams */ - const TEAM_NOT_FOUND = 'team_not_found'; - const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; - const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; - const TEAM_INVALID_SECRET = 'team_invalid_secret'; - const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; - const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; + const TEAM_NOT_FOUND = 'team_not_found'; + const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; + const TEAM_INVITE_NOT_FOUND = 'team_invite_not_found'; + const TEAM_INVALID_SECRET = 'team_invalid_secret'; + const TEAM_MEMBERSHIP_MISMATCH = 'team_membership_mismatch'; + const TEAM_INVITE_MISMATCH = 'team_invite_mismatch'; /** Membership */ - const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; + const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; /** Avatars */ - const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; - const AVATAR_NOT_FOUND = 'avatar_not_found'; - const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; - const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; - const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; + const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; + const AVATAR_NOT_FOUND = 'avatar_not_found'; + const AVATAR_IMAGE_NOT_FOUND = 'avatar_image_not_found'; + const AVATAR_REMOTE_URL_FAILED = 'avatar_remote_url_failed'; + const AVATAR_ICON_NOT_FOUND = 'avatar_icon_not_found'; /** Storage */ - const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; - const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; - const STORAGE_FILE_EMPTY = 'storage_file_empty'; - const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; - const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; - const STORAGE_INVALID_FILE = 'storage_invalid_file'; + const STORAGE_FILE_NOT_FOUND = 'storage_file_not_found'; + const STORAGE_DEVICE_NOT_FOUND = 'storage_device_not_found'; + const STORAGE_FILE_EMPTY = 'storage_file_empty'; + const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; + const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; + const STORAGE_INVALID_FILE = 'storage_invalid_file'; /** Functions */ - const FUNCTION_NOT_FOUND = 'function_not_found'; + const FUNCTION_NOT_FOUND = 'function_not_found'; /** Deployments */ - const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; + const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; /** Execution */ - const EXECUTION_NOT_FOUND = 'execution_not_found'; + const EXECUTION_NOT_FOUND = 'execution_not_found'; /** Collections */ - const COLLECTION_NOT_FOUND = 'collection_not_found'; - const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; - const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; - + const COLLECTION_NOT_FOUND = 'collection_not_found'; + const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; + const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; /** Documents */ - const DOCUMENT_NOT_FOUND = 'document_not_found'; - const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; - const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; - const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; + + const DOCUMENT_NOT_FOUND = 'document_not_found'; + const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; + const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; + const DOCUMENT_ALREADY_EXISTS = 'document_already_exists'; /** Attribute */ - const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; - const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; - const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; - const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; - const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; - const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; - const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; - const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; + const ATTRIBUTE_NOT_FOUND = 'attribute_not_found'; + const ATTRIBUTE_UNKNOWN = 'attribute_unknown'; + const ATTRIBUTE_NOT_AVAILABLE = 'attribute_not_available'; + const ATTRIBUTE_FORMAT_UNSUPPORTED = 'attribute_format_unsupported'; + const ATTRIBUTE_DEFAULT_UNSUPPORTED = 'attribute_default_unsupported'; + const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists'; + const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded'; + const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid'; /** Indexes */ - const INDEX_NOT_FOUND = 'index_not_found'; - const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; - const INDEX_ALREADY_EXISTS = 'index_already_exists'; + const INDEX_NOT_FOUND = 'index_not_found'; + const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; + const INDEX_ALREADY_EXISTS = 'index_already_exists'; /** Query limit exceeded */ - const QUERY_LIMIT_EXCEEDED = 'query_limit_exceeded'; - const QUERY_INVALID = 'query_invalid'; + const QUERY_LIMIT_EXCEEDED = 'query_limit_exceeded'; + const QUERY_INVALID = 'query_invalid'; /** Projects */ - const PROJECT_NOT_FOUND = 'project_not_found'; - const PROJECT_UNKNOWN = 'project_unknown'; + const PROJECT_NOT_FOUND = 'project_not_found'; + const PROJECT_UNKNOWN = 'project_unknown'; /** Webhooks */ - const WEBHOOK_NOT_FOUND = 'webhook_not_found'; + const WEBHOOK_NOT_FOUND = 'webhook_not_found'; /** Keys */ - const KEY_NOT_FOUND = 'key_not_found'; + const KEY_NOT_FOUND = 'key_not_found'; /** Platform */ - const PLATFORM_NOT_FOUND = 'platform_not_found'; + const PLATFORM_NOT_FOUND = 'platform_not_found'; /** Domain */ - const DOMAIN_NOT_FOUND = 'domain_not_found'; - const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; - const DOMAIN_UNREACHABLE = 'domain_unreachable'; - const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; + const DOMAIN_NOT_FOUND = 'domain_not_found'; + const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; + const DOMAIN_UNREACHABLE = 'domain_unreachable'; + const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; /** General */ - const GENERAL_DEFAULT = 'general_default'; - const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; - const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; - const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; - const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; - const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; - const GENERAL_SERVER_ERROR = 'general_server_error'; + const GENERAL_DEFAULT = 'general_default'; + const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + const GENERAL_SERVER_ERROR = 'general_server_error'; private $errorCode = ''; From c861d3c52ff9fbdbc2c959fa496842fa59a30cb3 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:42:03 +0400 Subject: [PATCH 65/95] feat: adjust docs --- src/Appwrite/Extend/Exception.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index e4709a31d6..bac2744c33 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -14,14 +14,25 @@ class Exception extends \Exception * * Appwrite has the follwing entities: * - Users - * - Projects - * - Sessions + * - OAuth * - Teams * - Memberships - * - Files + * - Avatars + * - Storage * - Functions * - Deployments * - Executions + * - Collections + * - Documents + * - Attributes + * - Indexes + * - Queries + * - Projects + * - Webhooks + * - Keys + * - Platform + * - Domain + * - General */ /** Users */ @@ -89,8 +100,8 @@ class Exception extends \Exception const COLLECTION_NOT_FOUND = 'collection_not_found'; const COLLECTION_ALREADY_EXISTS = 'collection_already_exists'; const COLLECTION_LIMIT_EXCEEDED = 'collection_limit_exceeded'; - /** Documents */ + /** Documents */ const DOCUMENT_NOT_FOUND = 'document_not_found'; const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure'; const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload'; From 847abadd397c50d0c31cf70659edf6a1fe44f30f Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 01:46:47 +0400 Subject: [PATCH 66/95] feat: add type attribute to returned error --- app/config/errors.php | 17 ++++++++++++++++- app/controllers/general.php | 2 ++ src/Appwrite/Extend/Exception.php | 12 +++++------- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index bfd95622a7..75293f46dd 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -8,6 +8,16 @@ use Appwrite\Extend\Exception; return [ /** General Errors */ + Exception::GENERAL_DEFAULT => [ + 'name' => Exception::GENERAL_DEFAULT, + 'description' => 'Default error', + 'code' => 500, + ], + Exception::GENERAL_ACCESS_FORBIDDEN => [ + 'name' => Exception::GENERAL_ACCESS_FORBIDDEN, + 'description' => 'Access forbidden', + 'code' => 403, + ], Exception::GENERAL_UNKNOWN_ORIGIN => [ 'name' => Exception::GENERAL_UNKNOWN_ORIGIN, 'description' => 'The request originated from a non-whitelisted origin. If you trust this origin, please add it as a platform in the Appwrite console.', @@ -30,9 +40,14 @@ return [ ], Exception::GENERAL_SMTP_DISABLED => [ 'name' => Exception::GENERAL_SMTP_DISABLED, - 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project ', + 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project.', 'code' => 503, ], + Exception::GENERAL_SERVER_ERROR => [ + 'name' => Exception::GENERAL_SERVER_ERROR, + 'description' => 'Internal server error.', + 'code' => 500, + ], /** Project Errors */ Exception::PROJECT_NOT_FOUND => [ diff --git a/app/controllers/general.php b/app/controllers/general.php index ee7485fe83..c243b56b46 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -431,10 +431,12 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l 'line' => $error->getLine(), 'trace' => $error->getTrace(), 'version' => $version, + 'type' => $error->getType(), ] : [ 'message' => $message, 'code' => $code, 'version' => $version, + 'type' => $error->getType(), ]; $response diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index bac2744c33..d65bcb2d68 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -2,8 +2,6 @@ namespace Appwrite\Extend; -use Utopia\Config\Config; - class Exception extends \Exception { /** @@ -156,11 +154,11 @@ class Exception extends \Exception const GENERAL_SERVER_ERROR = 'general_server_error'; - private $errorCode = ''; + private $type = ''; - public function __construct(string $message, int $code = 0, string $errorCode = Exception::GENERAL_DEFAULT, \Throwable $previous = null) + public function __construct(string $message, int $code = 0, string $type = Exception::GENERAL_DEFAULT, \Throwable $previous = null) { - $this->errorCode = $errorCode; + $this->type = $type; parent::__construct($message, $code, $previous); } @@ -168,8 +166,8 @@ class Exception extends \Exception /** * @return string */ - public function getErrorCode(): string + public function getType(): string { - return $this->errorCode; + return $this->type; } } \ No newline at end of file From 44f7d85a6446022b565e0e36eea9991b3abd6fd2 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 02:55:53 +0400 Subject: [PATCH 67/95] feat: handle utopia exceptions --- app/controllers/general.php | 7 +++++++ src/Appwrite/Extend/Exception.php | 1 + 2 files changed, 8 insertions(+) diff --git a/app/controllers/general.php b/app/controllers/general.php index c243b56b46..25a4578420 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -387,6 +387,13 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l throw $error; } + /** Wrap all exceptions inside Appwrite\Extend\Exception */ + if ($error instanceof Utopia\Exception && $error->getCode() === 400) { + $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_ARGUMENT_INVALID, $error); + } else { + $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_DEFAULT, $error); + } + $template = ($route) ? $route->getLabel('error', null) : null; if (php_sapi_name() === 'cli') { diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d65bcb2d68..6b48534772 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -151,6 +151,7 @@ class Exception extends \Exception const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; const GENERAL_SERVER_ERROR = 'general_server_error'; From 959e0d24f8efdf28fa71f057d6208b7dbaaa32cc Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Mon, 7 Feb 2022 03:24:49 +0400 Subject: [PATCH 68/95] feat: use default exception --- src/Appwrite/Migration/Migration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 777d389279..31618cf0ca 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -8,7 +8,7 @@ use PDO; use Redis; use Swoole\Runtime; use Utopia\CLI\Console; -use Utopia\Exception; +use Exception; abstract class Migration { From 5e41aad0120354828a48b2f1436e3e907a047b3a Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 01:04:52 +0400 Subject: [PATCH 69/95] feat: remove unused imports --- app/controllers/web/home.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php index 124833427a..30e629a02f 100644 --- a/app/controllers/web/home.php +++ b/app/controllers/web/home.php @@ -1,14 +1,8 @@ Date: Tue, 8 Feb 2022 01:10:36 +0400 Subject: [PATCH 70/95] feat: rearrange errors --- app/config/errors.php | 94 +++++++++++++++---------------- src/Appwrite/Extend/Exception.php | 26 ++++----- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 75293f46dd..ea1b95d22f 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -49,53 +49,6 @@ return [ 'code' => 500, ], - /** Project Errors */ - Exception::PROJECT_NOT_FOUND => [ - 'name' => Exception::PROJECT_NOT_FOUND, - 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'code' => 404, - ], - Exception::PROJECT_UNKNOWN => [ - 'name' => Exception::PROJECT_UNKNOWN, - 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', - 'code' => 400, - ], - Exception::WEBHOOK_NOT_FOUND => [ - 'name' => Exception::WEBHOOK_NOT_FOUND, - 'description' => 'The requested webhook could not be found.', - 'code' => 404, - ], - Exception::KEY_NOT_FOUND => [ - 'name' => Exception::KEY_NOT_FOUND, - 'description' => 'The requested key could not be found.', - 'code' => 404, - ], - Exception::PLATFORM_NOT_FOUND => [ - 'name' => Exception::PLATFORM_NOT_FOUND, - 'description' => 'The requested platform could not be found.', - 'code' => 404, - ], - Exception::DOMAIN_NOT_FOUND => [ - 'name' => Exception::DOMAIN_NOT_FOUND, - 'description' => 'The requested domain could not be found.', - 'code' => 404, - ], - Exception::DOMAIN_ALREADY_EXISTS => [ - 'name' => Exception::DOMAIN_ALREADY_EXISTS, - 'description' => 'The requested domain already exists.', - 'code' => 409, - ], - Exception::DOMAIN_UNREACHABLE => [ - 'name' => Exception::DOMAIN_UNREACHABLE, - 'description' => 'The requested domain is not reachable.', - 'code' => 503, - ], - Exception::DOMAIN_VERIFICATION_FAILED => [ - 'name' => Exception::DOMAIN_VERIFICATION_FAILED, - 'description' => 'The requested domain verification failed.', - 'code' => 503, - ], - /** User Errors */ Exception::USER_COUNT_EXCEEDED => [ 'name' => Exception::USER_COUNT_EXCEEDED, @@ -439,4 +392,51 @@ return [ 'description' => 'The query is invalid.', 'code' => 400, ], + + /** Project Errors */ + Exception::PROJECT_NOT_FOUND => [ + 'name' => Exception::PROJECT_NOT_FOUND, + 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', + 'code' => 404, + ], + Exception::PROJECT_UNKNOWN => [ + 'name' => Exception::PROJECT_UNKNOWN, + 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', + 'code' => 400, + ], + Exception::WEBHOOK_NOT_FOUND => [ + 'name' => Exception::WEBHOOK_NOT_FOUND, + 'description' => 'The requested webhook could not be found.', + 'code' => 404, + ], + Exception::KEY_NOT_FOUND => [ + 'name' => Exception::KEY_NOT_FOUND, + 'description' => 'The requested key could not be found.', + 'code' => 404, + ], + Exception::PLATFORM_NOT_FOUND => [ + 'name' => Exception::PLATFORM_NOT_FOUND, + 'description' => 'The requested platform could not be found.', + 'code' => 404, + ], + Exception::DOMAIN_NOT_FOUND => [ + 'name' => Exception::DOMAIN_NOT_FOUND, + 'description' => 'The requested domain could not be found.', + 'code' => 404, + ], + Exception::DOMAIN_ALREADY_EXISTS => [ + 'name' => Exception::DOMAIN_ALREADY_EXISTS, + 'description' => 'The requested domain already exists.', + 'code' => 409, + ], + Exception::DOMAIN_UNREACHABLE => [ + 'name' => Exception::DOMAIN_UNREACHABLE, + 'description' => 'The requested domain is not reachable.', + 'code' => 503, + ], + Exception::DOMAIN_VERIFICATION_FAILED => [ + 'name' => Exception::DOMAIN_VERIFICATION_FAILED, + 'description' => 'The requested domain verification failed.', + 'code' => 503, + ] ]; \ No newline at end of file diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 6b48534772..84f64df4bd 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -11,6 +11,7 @@ class Exception extends \Exception * _ * * Appwrite has the follwing entities: + * - General * - Users * - OAuth * - Teams @@ -30,9 +31,19 @@ class Exception extends \Exception * - Keys * - Platform * - Domain - * - General */ + /** General */ + const GENERAL_DEFAULT = 'general_default'; + const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; + const GENERAL_SERVER_ERROR = 'general_server_error'; + /** Users */ const USER_COUNT_EXCEEDED = 'user_count_exceeded'; const USER_JWT_INVALID = 'user_jwt_invalid'; @@ -120,7 +131,7 @@ class Exception extends \Exception const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; const INDEX_ALREADY_EXISTS = 'index_already_exists'; - /** Query limit exceeded */ + /** Query */ const QUERY_LIMIT_EXCEEDED = 'query_limit_exceeded'; const QUERY_INVALID = 'query_invalid'; @@ -143,17 +154,6 @@ class Exception extends \Exception const DOMAIN_UNREACHABLE = 'domain_unreachable'; const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; - /** General */ - const GENERAL_DEFAULT = 'general_default'; - const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; - const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; - const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; - const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; - const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; - const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; - const GENERAL_SERVER_ERROR = 'general_server_error'; - private $type = ''; From 4649653d9f7f4abe2cb1047e2e930bc0dc0d145c Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:08:05 +0400 Subject: [PATCH 71/95] feat: add invalid argument error --- app/config/errors.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/config/errors.php b/app/config/errors.php index ea1b95d22f..db9c4aed6a 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -43,6 +43,11 @@ return [ 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project.', 'code' => 503, ], + Exception::GENERAL_ARGUMENT_INVALID => [ + 'name' => Exception::GENERAL_ARGUMENT_INVALID, + 'description' => 'Invalid argument', + 'code' => 400, + ], Exception::GENERAL_SERVER_ERROR => [ 'name' => Exception::GENERAL_SERVER_ERROR, 'description' => 'Internal server error.', From 196e038ecca633ce606a23a9da67b51cbe8ce637 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:10:49 +0400 Subject: [PATCH 72/95] feat: update error order --- app/config/errors.php | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index db9c4aed6a..7200f6f5ca 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -60,21 +60,36 @@ return [ 'description' => 'The current project has exceeded the maximum number of users. Please check your user limit in the Appwrite console.', 'code' => 501, ], - Exception::USER_EMAIL_NOT_WHITELISTED => [ - 'name' => Exception::USER_EMAIL_NOT_WHITELISTED, - 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', - 'code' => 401, - ], Exception::USER_JWT_INVALID => [ 'name' => Exception::USER_JWT_INVALID, 'description' => 'The JWT token is invalid. Please check the value of the X-Appwrite-JWT header to ensure the correct token is being used.', 'code' => 401, ], + Exception::USER_ALREADY_EXISTS => [ + 'name' => Exception::USER_ALREADY_EXISTS, + 'description' => 'A user with the same email ID already exists in your project.', + 'code' => 409, + ], + Exception::USER_BLOCKED => [ + 'name' => Exception::USER_BLOCKED, + 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', + 'code' => 401, + ], + Exception::USER_INVALID_TOKEN => [ + 'name' => Exception::USER_INVALID_TOKEN, + 'description' => 'Invalid token.', + 'code' => 401, + ], Exception::USER_PASSWORD_RESET_REQUIRED => [ 'name' => Exception::USER_PASSWORD_RESET_REQUIRED, 'description' => 'The current user requires a password reset.', 'code' => 412, ], + Exception::USER_EMAIL_NOT_WHITELISTED => [ + 'name' => Exception::USER_EMAIL_NOT_WHITELISTED, + 'description' => 'The user\'s email is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_EMAILS environment variable of your Appwrite server.', + 'code' => 401, + ], Exception::USER_IP_NOT_WHITELISTED => [ 'name' => Exception::USER_IP_NOT_WHITELISTED, 'description' => 'The user\'s IP address is not part of the whitelist. Please check the _APP_CONSOLE_WHITELIST_IPS environment variable of your Appwrite server.', @@ -85,21 +100,6 @@ return [ 'description' => 'Invalid credentials. Please check the email and password.', 'code' => 401, ], - Exception::USER_ALREADY_EXISTS => [ - 'name' => Exception::USER_ALREADY_EXISTS, - 'description' => 'A user with the same email ID already exists in your project.', - 'code' => 409, - ], - Exception::USER_INVALID_TOKEN => [ - 'name' => Exception::USER_INVALID_TOKEN, - 'description' => 'Invalid token.', - 'code' => 401, - ], - Exception::USER_BLOCKED => [ - 'name' => Exception::USER_BLOCKED, - 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', - 'code' => 401, - ], Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED => [ 'name' => Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, 'description' => 'Anonymous users cannot be created for console project.', From f540ebd3d9e8ff3a13d026c0bf3dd12459b67942 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:12:26 +0400 Subject: [PATCH 73/95] feat: update error order --- src/Appwrite/Extend/Exception.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 84f64df4bd..7ee8f1d513 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -50,18 +50,18 @@ class Exception extends \Exception const USER_ALREADY_EXISTS = 'user_already_exists'; const USER_BLOCKED = 'user_blocked'; const USER_INVALID_TOKEN = 'user_invalid_token'; - const USER_NOT_FOUND = 'user_not_found'; - const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; - const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; - const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; - const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; const USER_PASSWORD_RESET_REQUIRED = 'user_password_reset_required'; const USER_EMAIL_NOT_WHITELISTED = 'user_email_not_whitelisted'; const USER_IP_NOT_WHITELISTED = 'user_ip_not_whitelisted'; + const USER_INVALID_CREDENTIALS = 'user_invalid_credentials'; + const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; const USER_SESSION_ALREADY_EXISTS = 'user_session_already_exists'; + const USER_NOT_FOUND = 'user_not_found'; + const USER_EMAIL_ALREADY_EXISTS = 'user_email_already_exists'; + const USER_PASSWORD_MISMATCH = 'user_password_mismatch'; const USER_SESSION_NOT_FOUND = 'user_session_not_found'; const USER_UNAUTHORIZED = 'user_unauthorized'; - const USER_ANONYMOUS_CONSOLE_PROHIBITED = 'user_anonymous_console_prohibited'; + const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; /** OAuth **/ const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; From 8dfc56cbde9ed51205682f33c2cc66d712e0c504 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:16:02 +0400 Subject: [PATCH 74/95] feat: remove prefix from general errors --- src/Appwrite/Extend/Exception.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 7ee8f1d513..8596211f35 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -34,15 +34,15 @@ class Exception extends \Exception */ /** General */ - const GENERAL_DEFAULT = 'general_default'; - const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; - const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; - const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; - const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; - const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; - const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; - const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; - const GENERAL_SERVER_ERROR = 'general_server_error'; + const GENERAL_DEFAULT = 'default'; + const GENERAL_ACCESS_FORBIDDEN = 'access_forbidden'; + const GENERAL_UNKNOWN_ORIGIN = 'unknown_origin'; + const GENERAL_SERVICE_DISABLED = 'service_disabled'; + const GENERAL_UNAUTHORIZED_SCOPE = 'unauthorized_scope'; + const GENERAL_RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; + const GENERAL_SMTP_DISABLED = 'smtp_disabled'; + const GENERAL_ARGUMENT_INVALID = 'argument_invalid'; + const GENERAL_SERVER_ERROR = 'server_error'; /** Users */ const USER_COUNT_EXCEEDED = 'user_count_exceeded'; From 073ab5565f91b1c78b386b710b3baa217cad2c02 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:17:23 +0400 Subject: [PATCH 75/95] feat: rename default to unknown --- app/config/errors.php | 4 ++-- app/controllers/general.php | 2 +- src/Appwrite/Extend/Exception.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 7200f6f5ca..2b23b29702 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -8,8 +8,8 @@ use Appwrite\Extend\Exception; return [ /** General Errors */ - Exception::GENERAL_DEFAULT => [ - 'name' => Exception::GENERAL_DEFAULT, + Exception::GENERAL_UNKNOWN => [ + 'name' => Exception::GENERAL_UNKNOWN, 'description' => 'Default error', 'code' => 500, ], diff --git a/app/controllers/general.php b/app/controllers/general.php index 25a4578420..b26b343072 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -391,7 +391,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l if ($error instanceof Utopia\Exception && $error->getCode() === 400) { $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_ARGUMENT_INVALID, $error); } else { - $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_DEFAULT, $error); + $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_UNKNOWN, $error); } $template = ($route) ? $route->getLabel('error', null) : null; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 8596211f35..113e17e230 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -34,7 +34,7 @@ class Exception extends \Exception */ /** General */ - const GENERAL_DEFAULT = 'default'; + const GENERAL_UNKNOWN = 'unknown'; const GENERAL_ACCESS_FORBIDDEN = 'access_forbidden'; const GENERAL_UNKNOWN_ORIGIN = 'unknown_origin'; const GENERAL_SERVICE_DISABLED = 'service_disabled'; @@ -157,7 +157,7 @@ class Exception extends \Exception private $type = ''; - public function __construct(string $message, int $code = 0, string $type = Exception::GENERAL_DEFAULT, \Throwable $previous = null) + public function __construct(string $message, int $code = 0, string $type = Exception::GENERAL_UNKNOWN, \Throwable $previous = null) { $this->type = $type; From f65b3ca18dccc061967e7a26ca7520846230b8ee Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:27:46 +0400 Subject: [PATCH 76/95] feat: update descriptions of general errors --- app/config/errors.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 2b23b29702..3defee74b2 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -10,17 +10,17 @@ return [ /** General Errors */ Exception::GENERAL_UNKNOWN => [ 'name' => Exception::GENERAL_UNKNOWN, - 'description' => 'Default error', + 'description' => 'An unknown error has occured. Please check the logs for more information.', 'code' => 500, ], Exception::GENERAL_ACCESS_FORBIDDEN => [ 'name' => Exception::GENERAL_ACCESS_FORBIDDEN, - 'description' => 'Access forbidden', - 'code' => 403, + 'description' => 'Access to this API is forbidden.', + 'code' => 401, ], Exception::GENERAL_UNKNOWN_ORIGIN => [ 'name' => Exception::GENERAL_UNKNOWN_ORIGIN, - 'description' => 'The request originated from a non-whitelisted origin. If you trust this origin, please add it as a platform in the Appwrite console.', + 'description' => 'The request originated from an unknown origin. If you trust this domain, please list it as a trusted platform in the Appwrite console.', 'code' => 403, ], Exception::GENERAL_SERVICE_DISABLED => [ @@ -40,17 +40,17 @@ return [ ], Exception::GENERAL_SMTP_DISABLED => [ 'name' => Exception::GENERAL_SMTP_DISABLED, - 'description' => 'SMTP is disabled on your Appwrite instance. Please contact your project.', + 'description' => 'SMTP is disabled on your Appwrite instance. Please contact the project owner.', 'code' => 503, ], Exception::GENERAL_ARGUMENT_INVALID => [ 'name' => Exception::GENERAL_ARGUMENT_INVALID, - 'description' => 'Invalid argument', + 'description' => 'The request contains one or more invalid arguments. Please refer to the endpoint documentation.', 'code' => 400, ], Exception::GENERAL_SERVER_ERROR => [ 'name' => Exception::GENERAL_SERVER_ERROR, - 'description' => 'Internal server error.', + 'description' => 'An internal server error occurred.', 'code' => 500, ], From 40977d82a947c172b2402e803ef403fbf76ff756 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:39:53 +0400 Subject: [PATCH 77/95] feat: update descriptions of users errors --- app/config/errors.php | 12 ++++++------ app/controllers/api/database.php | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 3defee74b2..78f8c7be12 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -72,12 +72,12 @@ return [ ], Exception::USER_BLOCKED => [ 'name' => Exception::USER_BLOCKED, - 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', + 'description' => 'The current user has been blocked. Please contact the project owner for more information.', 'code' => 401, ], Exception::USER_INVALID_TOKEN => [ 'name' => Exception::USER_INVALID_TOKEN, - 'description' => 'Invalid token.', + 'description' => 'Invalid token passed in the request.', 'code' => 401, ], Exception::USER_PASSWORD_RESET_REQUIRED => [ @@ -102,12 +102,12 @@ return [ ], Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED => [ 'name' => Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED, - 'description' => 'Anonymous users cannot be created for console project.', + 'description' => 'Anonymous users cannot be created for the console project.', 'code' => 401, ], Exception::USER_SESSION_ALREADY_EXISTS => [ 'name' => Exception::USER_SESSION_ALREADY_EXISTS, - 'description' => 'Cannot create anonymous user when a session is active.', + 'description' => 'Creation of anonymous users is prohibited when a session is active.', 'code' => 401, ], Exception::USER_NOT_FOUND => [ @@ -122,7 +122,7 @@ return [ ], Exception::USER_PASSWORD_MISMATCH => [ 'name' => Exception::USER_PASSWORD_MISMATCH, - 'description' => 'Passwords do not match. Please recheck.', + 'description' => 'Passwords do not match. Please check the password and confirm password.', 'code' => 400, ], Exception::USER_SESSION_NOT_FOUND => [ @@ -137,7 +137,7 @@ return [ ], Exception::USER_AUTH_METHOD_UNSUPPORTED => [ 'name' => Exception::USER_AUTH_METHOD_UNSUPPORTED, - 'description' => 'The requested authentication method is either disabled or unsupported.', + 'description' => 'The requested authentication method is either disabled or unsupported. Please check the supported authentication methods in the Appwrite console.', 'code' => 501, ], diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 9df02ddaf5..27b88bcea5 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1628,6 +1628,7 @@ App::post('/v1/database/collections/:collectionId/documents') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($data['$read'] as $read) { if (!Authorization::isRole($read)) { + // TODO: Isn't this a 401: Unauthorized Error ? throw new Exception('Read permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED); } } From 97c7513faa4c2d4b45af7533da7d37d759a0dadf Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:44:02 +0400 Subject: [PATCH 78/95] feat: update descriptions of oauth errors --- app/config/errors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index 78f8c7be12..ea87cff27e 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -149,7 +149,7 @@ return [ ], Exception::OAUTH_PROVIDER_UNSUPPORTED => [ 'name' => Exception::OAUTH_PROVIDER_UNSUPPORTED, - 'description' => 'The chosen OAuth provider is unsupported.', + 'description' => 'The chosen OAuth provider is unsupported. Please check the docs for the complete list of supported OAuth providers.', 'code' => 501, ], Exception::OAUTH_INVALID_SUCCESS_URL => [ From 35cd17290e495fc2086906ddc95b690a6ba77810 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:48:05 +0400 Subject: [PATCH 79/95] feat: update descriptions of temas errors --- app/config/errors.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index ea87cff27e..864d033c4e 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -164,7 +164,7 @@ return [ ], Exception::OAUTH_MISSING_USER_ID => [ 'name' => Exception::OAUTH_MISSING_USER_ID, - 'description' => 'Failed to obtain user id from the OAuth provider.', + 'description' => 'Failed to obtain user ID from the OAuth provider.', 'code' => 400, ], @@ -176,13 +176,13 @@ return [ ], Exception::TEAM_INVITE_ALREADY_EXISTS => [ 'name' => Exception::TEAM_INVITE_ALREADY_EXISTS, - 'description' => 'The current user already has an invitation to this team.', + 'description' => 'The current user has already received an invitation to join the team.', 'code' => 409, ], Exception::TEAM_INVITE_NOT_FOUND => [ 'name' => Exception::TEAM_INVITE_NOT_FOUND, - 'description' => 'The requested invitation could not be found.', - 'code' => 409, + 'description' => 'The requested team invitation could not be found.', + 'code' => 404, ], Exception::TEAM_INVALID_SECRET => [ 'name' => Exception::TEAM_INVALID_SECRET, From e600fc948388530a88430d925ec0ad031b850ed0 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 02:58:20 +0400 Subject: [PATCH 80/95] feat: update descriptions of avatars errors --- app/config/errors.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 864d033c4e..89fc6c7be9 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -221,12 +221,12 @@ return [ ], Exception::AVATAR_IMAGE_NOT_FOUND => [ 'name' => Exception::AVATAR_IMAGE_NOT_FOUND, - 'description' => 'The requested image was not found.', + 'description' => 'The requested image was not found at the URL.', 'code' => 404, ], Exception::AVATAR_REMOTE_URL_FAILED => [ 'name' => Exception::AVATAR_REMOTE_URL_FAILED, - 'description' => 'The remote URL could not be fetched.', + 'description' => 'Failed to fetch favicon from the requested URL.', 'code' => 404, ], Exception::AVATAR_ICON_NOT_FOUND => [ From 4934736e2d330b05b93b607def11281667c72e8e Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 03:01:28 +0400 Subject: [PATCH 81/95] feat: update descriptions of storage errors --- app/config/errors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index 89fc6c7be9..eb4143eab6 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -258,7 +258,7 @@ return [ ], Exception::STORAGE_INVALID_FILE_SIZE => [ 'name' => Exception::STORAGE_INVALID_FILE_SIZE, - 'description' => 'The file size is either not valid or exceeds the maximum allowed size.', + 'description' => 'The file size is either not valid or exceeds the maximum allowed size. Please check the file or the value of the _APP_STORAGE_LIMIT environment variable.', 'code' => 400, ], Exception::STORAGE_INVALID_FILE => [ From e7cfa206e56ec274cea85dae6605f4979108be17 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 03:04:06 +0400 Subject: [PATCH 82/95] feat: update descriptions of functions errors --- app/config/errors.php | 6 +++--- app/controllers/api/functions.php | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index eb4143eab6..92055eb4d2 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -270,21 +270,21 @@ return [ /** Functions */ Exception::FUNCTION_NOT_FOUND => [ 'name' => Exception::FUNCTION_NOT_FOUND, - 'description' => 'The requested function could not be found.', + 'description' => 'Function with the requested ID could not be found.', 'code' => 404, ], /** Deployments */ Exception::DEPLOYMENT_NOT_FOUND => [ 'name' => Exception::DEPLOYMENT_NOT_FOUND, - 'description' => 'The requested deployment could not be found.', + 'description' => 'Deployment with the requested ID could not be found.', 'code' => 404, ], /** Executions */ Exception::EXECUTION_NOT_FOUND => [ 'name' => Exception::EXECUTION_NOT_FOUND, - 'description' => 'The requested execution could not be found.', + 'description' => 'Execution with the requested ID could not be found.', 'code' => 404, ], diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index d592ae2670..9e12558406 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -554,6 +554,7 @@ App::get('/v1/functions/:functionId/tags') $cursorTag = $dbForProject->getDocument('tags', $cursor); if ($cursorTag->isEmpty()) { + // TODO: Shouldn't this be a 404 error ? throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400, Exception::DEPLOYMENT_NOT_FOUND); } } @@ -807,6 +808,8 @@ App::get('/v1/functions/:functionId/executions') $cursorExecution = $dbForProject->getDocument('executions', $cursor); if ($cursorExecution->isEmpty()) { + // TODO: Shouldn't this be a 404 error ? + // Or do we define a new error type GENERAL_CURSOR_NOT_FOUND for these types ? throw new Exception("Execution '{$cursor}' for the 'cursor' value not found.", 400, Exception::EXECUTION_NOT_FOUND); } } From d504ef260728e798123c3ddf7a03f3f10aeecad5 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 03:17:52 +0400 Subject: [PATCH 83/95] feat: update descriptions of database errors --- app/config/errors.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 92055eb4d2..d8a1068f4b 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -291,13 +291,13 @@ return [ /** Collections */ Exception::COLLECTION_NOT_FOUND => [ 'name' => Exception::COLLECTION_NOT_FOUND, - 'description' => 'The requested collection could not be found.', + 'description' => 'Collection with the requested ID could not be found.', 'code' => 404, ], Exception::COLLECTION_ALREADY_EXISTS => [ 'name' => Exception::COLLECTION_ALREADY_EXISTS, - 'description' => 'The collection already exists.', - 'code' => 400, + 'description' => 'A collection with the requested ID already exists.', + 'code' => 409, ], Exception::COLLECTION_LIMIT_EXCEEDED => [ 'name' => Exception::COLLECTION_LIMIT_EXCEEDED, @@ -308,12 +308,12 @@ return [ /** Documents */ Exception::DOCUMENT_NOT_FOUND => [ 'name' => Exception::DOCUMENT_NOT_FOUND, - 'description' => 'The requested document could not be found.', + 'description' => 'Document with the requested ID could not be found.', 'code' => 404, ], Exception::DOCUMENT_INVALID_STRUCTURE => [ 'name' => Exception::DOCUMENT_INVALID_STRUCTURE, - 'description' => 'The document structure is invalid.', + 'description' => 'The document structure is invalid. Please ensure the attributes match the collection definition.', 'code' => 400, ], Exception::DOCUMENT_MISSING_PAYLOAD => [ @@ -323,25 +323,25 @@ return [ ], Exception::DOCUMENT_ALREADY_EXISTS => [ 'name' => Exception::DOCUMENT_ALREADY_EXISTS, - 'description' => 'The document already exists.', - 'code' => 400, + 'description' => 'Document with the requested ID already exists.', + 'code' => 409, ], /** Attributes */ Exception::ATTRIBUTE_NOT_FOUND => [ 'name' => Exception::ATTRIBUTE_NOT_FOUND, - 'description' => 'The requested attribute could not be found.', + 'description' => 'Attribute with the requested ID could not be found.', 'code' => 404, ], Exception::ATTRIBUTE_UNKNOWN => [ 'name' => Exception::ATTRIBUTE_UNKNOWN, - 'description' => 'The requested attribute could not be found.', - 'code' => 404, + 'description' => 'The attribute required for the index could not be found. Please confirm all your attributes are in the available state.', + 'code' => 400, ], Exception::ATTRIBUTE_NOT_AVAILABLE => [ 'name' => Exception::ATTRIBUTE_NOT_AVAILABLE, - 'description' => 'The requested attribute is not available.', - 'code' => 404, + 'description' => 'The requested attribute is not yet available. Please try again later.', + 'code' => 400, ], Exception::ATTRIBUTE_FORMAT_UNSUPPORTED => [ 'name' => Exception::ATTRIBUTE_FORMAT_UNSUPPORTED, @@ -350,13 +350,13 @@ return [ ], Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED => [ 'name' => Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, - 'description' => 'The requested attribute default value is not supported.', + 'description' => 'Default values cannot be set for array and required attributes.', 'code' => 400, ], Exception::ATTRIBUTE_ALREADY_EXISTS => [ 'name' => Exception::ATTRIBUTE_ALREADY_EXISTS, - 'description' => 'The attribute already exists.', - 'code' => 400, + 'description' => 'Attribute with the requested ID already exists.', + 'code' => 409, ], Exception::ATTRIBUTE_LIMIT_EXCEEDED => [ 'name' => Exception::ATTRIBUTE_LIMIT_EXCEEDED, @@ -365,14 +365,14 @@ return [ ], Exception::ATTRIBUTE_VALUE_INVALID => [ 'name' => Exception::ATTRIBUTE_VALUE_INVALID, - 'description' => 'The attribute value is invalid.', + 'description' => 'The attribute value is invalid. Please check the type, range and value of the attribute.', 'code' => 400, ], /** Indexes */ Exception::INDEX_NOT_FOUND => [ 'name' => Exception::INDEX_NOT_FOUND, - 'description' => 'The requested index could not be found.', + 'description' => 'Index with the requested could not be found.', 'code' => 404, ], Exception::INDEX_LIMIT_EXCEEDED => [ @@ -382,19 +382,19 @@ return [ ], Exception::INDEX_ALREADY_EXISTS => [ 'name' => Exception::INDEX_ALREADY_EXISTS, - 'description' => 'The index already exists.', - 'code' => 400, + 'description' => 'Index with the requested ID already exists.', + 'code' => 409, ], /** Query */ Exception::QUERY_LIMIT_EXCEEDED => [ 'name' => Exception::QUERY_LIMIT_EXCEEDED, - 'description' => 'The maximum number of results has been reached.', + 'description' => 'Query limit exceeded for the current attribute. Usage of more than 100 query values on a single attribute is prohibited.', 'code' => 400, ], Exception::QUERY_INVALID => [ 'name' => Exception::QUERY_INVALID, - 'description' => 'The query is invalid.', + 'description' => 'Your query syntax is invalid. Please check your query and try again.', 'code' => 400, ], From 12794f421417ed7bf2e1f3637673407addabe548 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 03:23:07 +0400 Subject: [PATCH 84/95] feat: update descriptions of projects errors --- app/config/errors.php | 21 ++++++++------------- app/controllers/api/projects.php | 5 +++-- src/Appwrite/Extend/Exception.php | 1 - 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index d8a1068f4b..77c132f0fa 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -401,7 +401,7 @@ return [ /** Project Errors */ Exception::PROJECT_NOT_FOUND => [ 'name' => Exception::PROJECT_NOT_FOUND, - 'description' => 'The requested project could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', + 'description' => 'Project with the requested ID could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', 'code' => 404, ], Exception::PROJECT_UNKNOWN => [ @@ -411,37 +411,32 @@ return [ ], Exception::WEBHOOK_NOT_FOUND => [ 'name' => Exception::WEBHOOK_NOT_FOUND, - 'description' => 'The requested webhook could not be found.', + 'description' => 'Webhook with the requested ID could not be found.', 'code' => 404, ], Exception::KEY_NOT_FOUND => [ 'name' => Exception::KEY_NOT_FOUND, - 'description' => 'The requested key could not be found.', + 'description' => 'Key with the requested ID could not be found.', 'code' => 404, ], Exception::PLATFORM_NOT_FOUND => [ 'name' => Exception::PLATFORM_NOT_FOUND, - 'description' => 'The requested platform could not be found.', + 'description' => 'Platform with the requested ID could not be found.', 'code' => 404, ], Exception::DOMAIN_NOT_FOUND => [ 'name' => Exception::DOMAIN_NOT_FOUND, - 'description' => 'The requested domain could not be found.', + 'description' => 'Domain with the requested ID could not be found.', 'code' => 404, ], Exception::DOMAIN_ALREADY_EXISTS => [ 'name' => Exception::DOMAIN_ALREADY_EXISTS, - 'description' => 'The requested domain already exists.', + 'description' => 'A Domain with the requested ID already exists.', 'code' => 409, ], - Exception::DOMAIN_UNREACHABLE => [ - 'name' => Exception::DOMAIN_UNREACHABLE, - 'description' => 'The requested domain is not reachable.', - 'code' => 503, - ], Exception::DOMAIN_VERIFICATION_FAILED => [ 'name' => Exception::DOMAIN_VERIFICATION_FAILED, - 'description' => 'The requested domain verification failed.', - 'code' => 503, + 'description' => 'Domain verification for the requested domain has failed.', + 'code' => 401, ] ]; \ No newline at end of file diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index df6ab569f0..cb2eb0e739 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1236,7 +1236,7 @@ App::post('/v1/projects/:projectId/domains') $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); if (!$target->isKnown() || $target->isTest()) { - throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500, Exception::DOMAIN_UNREACHABLE); + throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500, Exception::GENERAL_SERVER_ERROR); } $domain = new Domain($domain); @@ -1367,7 +1367,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); if (!$target->isKnown() || $target->isTest()) { - throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500, Exception::DOMAIN_UNREACHABLE); + throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500, Exception::GENERAL_SERVER_ERROR); } if ($domain->getAttribute('verification') === true) { @@ -1377,6 +1377,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $validator = new CNAME($target->get()); // Verify Domain with DNS records if (!$validator->isValid($domain->getAttribute('domain', ''))) { + // TODO: Isn't 401 Unauthorized ? Should we return a 400 Bad Request ? throw new Exception('Failed to verify domain', 401, Exception::DOMAIN_VERIFICATION_FAILED); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 113e17e230..3dfb02ff65 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -151,7 +151,6 @@ class Exception extends \Exception /** Domain */ const DOMAIN_NOT_FOUND = 'domain_not_found'; const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; - const DOMAIN_UNREACHABLE = 'domain_unreachable'; const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; From 96c058431d72f73b35b52f30e7785608425e75e1 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 8 Feb 2022 20:52:02 +0400 Subject: [PATCH 85/95] feat: add link to docs --- src/Appwrite/Utopia/Response/Model/Error.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/Error.php b/src/Appwrite/Utopia/Response/Model/Error.php index e12e0bd42c..20c91fa7c0 100644 --- a/src/Appwrite/Utopia/Response/Model/Error.php +++ b/src/Appwrite/Utopia/Response/Model/Error.php @@ -24,8 +24,8 @@ class Error extends Model ]) ->addRule('type', [ 'type' => self::TYPE_STRING, - 'description' => 'Error type.', - 'default' => '', + 'description' => 'Error type. You can learn more about all the error types at https://appwrite.io/docs/error-codes#errorTypes', + 'default' => 'unknown', 'example' => 'not_found', ]) ->addRule('version', [ From 0833662606572eec34c8aa067575b0681f2af03b Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 9 Feb 2022 01:25:52 +0400 Subject: [PATCH 86/95] feat: move oauth errors to projects --- app/config/errors.php | 52 +++++++++++++++---------------- app/controllers/api/account.php | 12 +++---- src/Appwrite/Extend/Exception.php | 30 +++++++++--------- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 77c132f0fa..44e8401e6e 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -141,33 +141,6 @@ return [ 'code' => 501, ], - /** OAuth Errors */ - Exception::OAUTH_PROVIDER_DISABLED => [ - 'name' => Exception::OAUTH_PROVIDER_DISABLED, - 'description' => 'The chosen OAuth provider is disabled. Please contact your project administrator for more information.', - 'code' => 412, - ], - Exception::OAUTH_PROVIDER_UNSUPPORTED => [ - 'name' => Exception::OAUTH_PROVIDER_UNSUPPORTED, - 'description' => 'The chosen OAuth provider is unsupported. Please check the docs for the complete list of supported OAuth providers.', - 'code' => 501, - ], - Exception::OAUTH_INVALID_SUCCESS_URL => [ - 'name' => Exception::OAUTH_INVALID_SUCCESS_URL, - 'description' => 'Invalid URL received for OAuth success redirect.', - 'code' => 400, - ], - Exception::OAUTH_INVALID_FAILURE_URL => [ - 'name' => Exception::OAUTH_INVALID_FAILURE_URL, - 'description' => 'Invalid URL received for OAuth failure redirect.', - 'code' => 400, - ], - Exception::OAUTH_MISSING_USER_ID => [ - 'name' => Exception::OAUTH_MISSING_USER_ID, - 'description' => 'Failed to obtain user ID from the OAuth provider.', - 'code' => 400, - ], - /** Teams */ Exception::TEAM_NOT_FOUND => [ 'name' => Exception::TEAM_NOT_FOUND, @@ -409,6 +382,31 @@ return [ 'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.', 'code' => 400, ], + Exception::PROJECT_PROVIDER_DISABLED => [ + 'name' => Exception::PROJECT_PROVIDER_DISABLED, + 'description' => 'The chosen OAuth provider is disabled. Please contact your project administrator for more information.', + 'code' => 412, + ], + Exception::PROJECT_PROVIDER_UNSUPPORTED => [ + 'name' => Exception::PROJECT_PROVIDER_UNSUPPORTED, + 'description' => 'The chosen OAuth provider is unsupported. Please check the docs for the complete list of supported OAuth providers.', + 'code' => 501, + ], + Exception::PROJECT_INVALID_SUCCESS_URL => [ + 'name' => Exception::PROJECT_INVALID_SUCCESS_URL, + 'description' => 'Invalid URL received for OAuth success redirect.', + 'code' => 400, + ], + Exception::PROJECT_INVALID_FAILURE_URL => [ + 'name' => Exception::PROJECT_INVALID_FAILURE_URL, + 'description' => 'Invalid URL received for OAuth failure redirect.', + 'code' => 400, + ], + Exception::PROJECT_MISSING_USER_ID => [ + 'name' => Exception::PROJECT_MISSING_USER_ID, + 'description' => 'Failed to obtain user ID from the OAuth provider.', + 'code' => 400, + ], Exception::WEBHOOK_NOT_FOUND => [ 'name' => Exception::WEBHOOK_NOT_FOUND, 'description' => 'Webhook with the requested ID could not be found.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 5fad398d19..69602dc42c 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -283,13 +283,13 @@ App::get('/v1/account/sessions/oauth2/:provider') } if (empty($appId) || empty($appSecret)) { - throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::OAUTH_PROVIDER_DISABLED); + throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::PROJECT_PROVIDER_DISABLED); } $className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider); if (!\class_exists($className)) { - throw new Exception('Provider is not supported', 501, Exception::OAUTH_PROVIDER_UNSUPPORTED); + throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED); } if(empty($success)) { @@ -407,7 +407,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); if (!\class_exists($className)) { - throw new Exception('Provider is not supported', 501, Exception::OAUTH_PROVIDER_UNSUPPORTED); + throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED); } $oauth2 = new $className($appId, $appSecret, $callback); @@ -423,11 +423,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if (!$validateURL->isValid($state['success'])) { - throw new Exception('Invalid redirect URL for success login', 400, Exception::OAUTH_INVALID_SUCCESS_URL); + throw new Exception('Invalid redirect URL for success login', 400, Exception::PROJECT_INVALID_SUCCESS_URL); } if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) { - throw new Exception('Invalid redirect URL for failure login', 400, Exception::OAUTH_INVALID_FAILURE_URL); + throw new Exception('Invalid redirect URL for failure login', 400, Exception::PROJECT_INVALID_FAILURE_URL); } $state['failure'] = null; @@ -451,7 +451,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $response->redirect($state['failure'], 301, 0); } - throw new Exception('Missing ID from OAuth2 provider', 400, Exception::OAUTH_MISSING_USER_ID); + throw new Exception('Missing ID from OAuth2 provider', 400, Exception::PROJECT_MISSING_USER_ID); } $sessions = $user->getAttribute('sessions', []); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 3dfb02ff65..d45e36904c 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -34,15 +34,15 @@ class Exception extends \Exception */ /** General */ - const GENERAL_UNKNOWN = 'unknown'; - const GENERAL_ACCESS_FORBIDDEN = 'access_forbidden'; - const GENERAL_UNKNOWN_ORIGIN = 'unknown_origin'; - const GENERAL_SERVICE_DISABLED = 'service_disabled'; - const GENERAL_UNAUTHORIZED_SCOPE = 'unauthorized_scope'; - const GENERAL_RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded'; - const GENERAL_SMTP_DISABLED = 'smtp_disabled'; - const GENERAL_ARGUMENT_INVALID = 'argument_invalid'; - const GENERAL_SERVER_ERROR = 'server_error'; + const GENERAL_UNKNOWN = 'general_unknown'; + const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; + const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; + const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; + const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope'; + const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; + const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; + const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; + const GENERAL_SERVER_ERROR = 'general_server_error'; /** Users */ const USER_COUNT_EXCEEDED = 'user_count_exceeded'; @@ -63,13 +63,6 @@ class Exception extends \Exception const USER_UNAUTHORIZED = 'user_unauthorized'; const USER_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported'; - /** OAuth **/ - const OAUTH_PROVIDER_DISABLED = 'oauth_provider_disabled'; - const OAUTH_PROVIDER_UNSUPPORTED = 'oauth_provider_unsupported'; - const OAUTH_INVALID_SUCCESS_URL = 'oauth_invalid_success_url'; - const OAUTH_INVALID_FAILURE_URL = 'oauth_invalid_failure_url'; - const OAUTH_MISSING_USER_ID = 'oauth_missing_user_id'; - /** Teams */ const TEAM_NOT_FOUND = 'team_not_found'; const TEAM_INVITE_ALREADY_EXISTS = 'team_invite_already_exists'; @@ -138,6 +131,11 @@ class Exception extends \Exception /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; const PROJECT_UNKNOWN = 'project_unknown'; + const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled'; + const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported'; + const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url'; + const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url'; + const PROJECT_MISSING_USER_ID = 'project_missing_user_id'; /** Webhooks */ const WEBHOOK_NOT_FOUND = 'webhook_not_found'; From d410dc5f3dd46c2c46245f400e0670119cd3bab8 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 9 Feb 2022 01:26:02 +0400 Subject: [PATCH 87/95] feat: move oauth errors to projects --- src/Appwrite/Extend/Exception.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index d45e36904c..4ce0995315 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -13,7 +13,6 @@ class Exception extends \Exception * Appwrite has the follwing entities: * - General * - Users - * - OAuth * - Teams * - Memberships * - Avatars From d5dd6a17b806d7e4d4f17f83b65bb2855d58b91f Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 9 Feb 2022 01:34:26 +0400 Subject: [PATCH 88/95] feat: move query errors to general category --- app/config/errors.php | 22 ++++++++++------------ app/controllers/api/database.php | 4 ++-- src/Appwrite/Extend/Exception.php | 7 ++----- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 44e8401e6e..700273e96a 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -48,6 +48,16 @@ return [ 'description' => 'The request contains one or more invalid arguments. Please refer to the endpoint documentation.', 'code' => 400, ], + Exception::GENERAL_QUERY_LIMIT_EXCEEDED => [ + 'name' => Exception::GENERAL_QUERY_LIMIT_EXCEEDED, + 'description' => 'Query limit exceeded for the current attribute. Usage of more than 100 query values on a single attribute is prohibited.', + 'code' => 400, + ], + Exception::GENERAL_QUERY_INVALID => [ + 'name' => Exception::GENERAL_QUERY_INVALID, + 'description' => 'The query\'s syntax is invalid. Please check the query and try again.', + 'code' => 400, + ], Exception::GENERAL_SERVER_ERROR => [ 'name' => Exception::GENERAL_SERVER_ERROR, 'description' => 'An internal server error occurred.', @@ -359,18 +369,6 @@ return [ 'code' => 409, ], - /** Query */ - Exception::QUERY_LIMIT_EXCEEDED => [ - 'name' => Exception::QUERY_LIMIT_EXCEEDED, - 'description' => 'Query limit exceeded for the current attribute. Usage of more than 100 query values on a single attribute is prohibited.', - 'code' => 400, - ], - Exception::QUERY_INVALID => [ - 'name' => Exception::QUERY_INVALID, - 'description' => 'Your query syntax is invalid. Please check your query and try again.', - 'code' => 400, - ], - /** Project Errors */ Exception::PROJECT_NOT_FOUND => [ 'name' => Exception::PROJECT_NOT_FOUND, diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 73e2c2cd1d..6a2041c93c 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1726,7 +1726,7 @@ App::get('/v1/database/collections/:collectionId/documents') $query = Query::parse($query); if (\count($query->getValues()) > 100) { - throw new Exception("You cannot use more than 100 query values on attribute '{$query->getAttribute()}'", 400, Exception::QUERY_LIMIT_EXCEEDED); + throw new Exception("You cannot use more than 100 query values on attribute '{$query->getAttribute()}'", 400, Exception::GENERAL_QUERY_LIMIT_EXCEEDED); } return $query; @@ -1735,7 +1735,7 @@ App::get('/v1/database/collections/:collectionId/documents') if (!empty($queries)) { $validator = new QueriesValidator(new QueryValidator($collection->getAttribute('attributes', [])), $collection->getAttribute('indexes', []), true); if (!$validator->isValid($queries)) { - throw new Exception($validator->getDescription(), 400, Exception::QUERY_INVALID); + throw new Exception($validator->getDescription(), 400, Exception::GENERAL_QUERY_INVALID); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 4ce0995315..a016f94c37 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -24,7 +24,6 @@ class Exception extends \Exception * - Documents * - Attributes * - Indexes - * - Queries * - Projects * - Webhooks * - Keys @@ -41,6 +40,8 @@ class Exception extends \Exception const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded'; const GENERAL_SMTP_DISABLED = 'general_smtp_disabled'; const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; + const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; + const GENERAL_QUERY_INVALID = 'general_query_invalid'; const GENERAL_SERVER_ERROR = 'general_server_error'; /** Users */ @@ -123,10 +124,6 @@ class Exception extends \Exception const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded'; const INDEX_ALREADY_EXISTS = 'index_already_exists'; - /** Query */ - const QUERY_LIMIT_EXCEEDED = 'query_limit_exceeded'; - const QUERY_INVALID = 'query_invalid'; - /** Projects */ const PROJECT_NOT_FOUND = 'project_not_found'; const PROJECT_UNKNOWN = 'project_unknown'; From debf882d021824103fc5fa38caa4f99859dc5f32 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 9 Feb 2022 02:47:48 +0400 Subject: [PATCH 89/95] feat: address review comments --- app/config/errors.php | 8 ++++---- app/controllers/api/projects.php | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 700273e96a..0ec2c08b55 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -25,7 +25,7 @@ return [ ], Exception::GENERAL_SERVICE_DISABLED => [ 'name' => Exception::GENERAL_SERVICE_DISABLED, - 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project owner.', + 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project administrator.', 'code' => 503, ], Exception::GENERAL_UNAUTHORIZED_SCOPE => [ @@ -40,7 +40,7 @@ return [ ], Exception::GENERAL_SMTP_DISABLED => [ 'name' => Exception::GENERAL_SMTP_DISABLED, - 'description' => 'SMTP is disabled on your Appwrite instance. Please contact the project owner.', + 'description' => 'SMTP is disabled on your Appwrite instance. Please contact the project administrator.', 'code' => 503, ], Exception::GENERAL_ARGUMENT_INVALID => [ @@ -82,7 +82,7 @@ return [ ], Exception::USER_BLOCKED => [ 'name' => Exception::USER_BLOCKED, - 'description' => 'The current user has been blocked. Please contact the project owner for more information.', + 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', 'code' => 401, ], Exception::USER_INVALID_TOKEN => [ @@ -355,7 +355,7 @@ return [ /** Indexes */ Exception::INDEX_NOT_FOUND => [ 'name' => Exception::INDEX_NOT_FOUND, - 'description' => 'Index with the requested could not be found.', + 'description' => 'Index with the requested ID could not be found.', 'code' => 404, ], Exception::INDEX_LIMIT_EXCEEDED => [ diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 0b2da9beb8..0157667c88 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1377,7 +1377,6 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $validator = new CNAME($target->get()); // Verify Domain with DNS records if (!$validator->isValid($domain->getAttribute('domain', ''))) { - // TODO: Isn't 401 Unauthorized ? Should we return a 400 Bad Request ? throw new Exception('Failed to verify domain', 401, Exception::DOMAIN_VERIFICATION_FAILED); } From 1ab27083c4c34cdb6aed786fcb2aa16d51b40d5a Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 9 Feb 2022 02:56:11 +0400 Subject: [PATCH 90/95] feat: update cursor errors --- app/config/errors.php | 5 +++++ app/controllers/api/database.php | 4 ++-- app/controllers/api/functions.php | 8 +++----- app/controllers/api/projects.php | 2 +- app/controllers/api/storage.php | 2 +- app/controllers/api/teams.php | 4 ++-- app/controllers/api/users.php | 2 +- src/Appwrite/Extend/Exception.php | 1 + 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 0ec2c08b55..3730a52d94 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -58,6 +58,11 @@ return [ 'description' => 'The query\'s syntax is invalid. Please check the query and try again.', 'code' => 400, ], + Exception::GENERAL_CURSOR_NOT_FOUND => [ + 'name' => Exception::GENERAL_CURSOR_NOT_FOUND, + 'description' => 'The cursor is invalid. This can happen if the item represented by the cursor has been deleted.', + 'code' => 400, + ], Exception::GENERAL_SERVER_ERROR => [ 'name' => Exception::GENERAL_SERVER_ERROR, 'description' => 'An internal server error occurred.', diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 6a2041c93c..ca56e080a3 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -225,7 +225,7 @@ App::get('/v1/database/collections') $cursorCollection = $dbForProject->getDocument('collections', $cursor); if ($cursorCollection->isEmpty()) { - throw new Exception("Collection '{$cursor}' for the 'cursor' value not found.", 400, Exception::COLLECTION_NOT_FOUND); + throw new Exception("Collection '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } @@ -1746,7 +1746,7 @@ App::get('/v1/database/collections/:collectionId/documents') : $dbForProject->getDocument('collection_' . $collectionId, $cursor); if ($cursorDocument->isEmpty()) { - throw new Exception("Document '{$cursor}' for the 'cursor' value not found.", 400, Exception::DOCUMENT_NOT_FOUND); + throw new Exception("Document '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index d7cdf111b4..c0babd59f0 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -103,7 +103,7 @@ App::get('/v1/functions') $cursorFunction = $dbForProject->getDocument('functions', $cursor); if ($cursorFunction->isEmpty()) { - throw new Exception("Function '{$cursor}' for the 'cursor' value not found.", 400, Exception::FUNCTION_NOT_FOUND); + throw new Exception("Function '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } @@ -555,7 +555,7 @@ App::get('/v1/functions/:functionId/tags') if ($cursorTag->isEmpty()) { // TODO: Shouldn't this be a 404 error ? - throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400, Exception::DEPLOYMENT_NOT_FOUND); + throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } @@ -808,9 +808,7 @@ App::get('/v1/functions/:functionId/executions') $cursorExecution = $dbForProject->getDocument('executions', $cursor); if ($cursorExecution->isEmpty()) { - // TODO: Shouldn't this be a 404 error ? - // Or do we define a new error type GENERAL_CURSOR_NOT_FOUND for these types ? - throw new Exception("Execution '{$cursor}' for the 'cursor' value not found.", 400, Exception::EXECUTION_NOT_FOUND); + throw new Exception("Execution '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 0157667c88..a06168918c 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -172,7 +172,7 @@ App::get('/v1/projects') $cursorProject = $dbForConsole->getDocument('projects', $cursor); if ($cursorProject->isEmpty()) { - throw new Exception("Project '{$cursor}' for the 'cursor' value not found.", 400, Exception::PROJECT_NOT_FOUND); + throw new Exception("Project '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 90842f6aa4..f42b8db82a 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -213,7 +213,7 @@ App::get('/v1/storage/files') $cursorFile = $dbForProject->getDocument('files', $cursor); if ($cursorFile->isEmpty()) { - throw new Exception("File '{$cursor}' for the 'cursor' value not found.", 400, Exception::STORAGE_FILE_NOT_FOUND); + throw new Exception("File '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 5a04493ed4..fb388a5c12 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -117,7 +117,7 @@ App::get('/v1/teams') $cursorTeam = $dbForProject->getDocument('teams', $cursor); if ($cursorTeam->isEmpty()) { - throw new Exception("Team '{$cursor}' for the 'cursor' value not found.", 400, Exception::TEAM_NOT_FOUND); + throw new Exception("Team '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } @@ -454,7 +454,7 @@ App::get('/v1/teams/:teamId/memberships') $cursorMembership = $dbForProject->getDocument('memberships', $cursor); if ($cursorMembership->isEmpty()) { - throw new Exception("Membership '{$cursor}' for the 'cursor' value not found.", 400, Exception::MEMBERSHIP_NOT_FOUND); + throw new Exception("Membership '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 61af807317..f8bc8ca154 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -110,7 +110,7 @@ App::get('/v1/users') $cursorUser = $dbForProject->getDocument('users', $cursor); if ($cursorUser->isEmpty()) { - throw new Exception("User '{$cursor}' for the 'cursor' value not found.", 404, Exception::USER_NOT_FOUND); + throw new Exception("User '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index a016f94c37..0db0c5ed6b 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -42,6 +42,7 @@ class Exception extends \Exception const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; const GENERAL_QUERY_INVALID = 'general_query_invalid'; + const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found'; const GENERAL_SERVER_ERROR = 'general_server_error'; /** Users */ From cb922827a45b8f0b181f5100767b22439d95d076 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 9 Feb 2022 03:08:23 +0400 Subject: [PATCH 91/95] feat: update cursor errors --- app/controllers/general.php | 8 +++++--- src/Appwrite/Extend/Exception.php | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index e05b57485c..55517fff93 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -376,11 +376,13 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l } /** Wrap all exceptions inside Appwrite\Extend\Exception */ - if ($error instanceof Utopia\Exception && $error->getCode() === 400) { - $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_ARGUMENT_INVALID, $error); - } else { + if (!($error instanceof Exception)) { $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_UNKNOWN, $error); } + + if ($error instanceof Utopia\Exception && $error->getCode() === 400) { + $error->setType(Exception::GENERAL_ARGUMENT_INVALID); + } $template = ($route) ? $route->getLabel('error', null) : null; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 0db0c5ed6b..5b05551b43 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -159,10 +159,25 @@ class Exception extends \Exception } /** + * Get the type of the exception. + * * @return string */ public function getType(): string { return $this->type; } + + /** + * Set the type of the exception. + * + * @param string $type + * + * @return void + */ + public function setType(string $type): void + { + $this->type = $type; + } + } \ No newline at end of file From 9af621c8c22aa33b8dd2c3a1477467bc6f6f0cb2 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 13 Feb 2022 12:37:14 +0400 Subject: [PATCH 92/95] feat: update error messages --- app/config/errors.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 3730a52d94..6398ac808d 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -25,7 +25,7 @@ return [ ], Exception::GENERAL_SERVICE_DISABLED => [ 'name' => Exception::GENERAL_SERVICE_DISABLED, - 'description' => 'The requested service is disabled. You can enable/disable a service from the Appwrite console or by contacting the project administrator.', + 'description' => 'The requested service is disabled. You can enable the service from the Appwrite console.', 'code' => 503, ], Exception::GENERAL_UNAUTHORIZED_SCOPE => [ @@ -40,7 +40,7 @@ return [ ], Exception::GENERAL_SMTP_DISABLED => [ 'name' => Exception::GENERAL_SMTP_DISABLED, - 'description' => 'SMTP is disabled on your Appwrite instance. Please contact the project administrator.', + 'description' => 'SMTP is disabled on your Appwrite instance. You can learn more about setting up SMTP in our docs.', 'code' => 503, ], Exception::GENERAL_ARGUMENT_INVALID => [ @@ -87,7 +87,7 @@ return [ ], Exception::USER_BLOCKED => [ 'name' => Exception::USER_BLOCKED, - 'description' => 'The current user has been blocked. Please contact the project administrator for more information.', + 'description' => 'The current user has been blocked. You can unblock the user from the Appwrite console.', 'code' => 401, ], Exception::USER_INVALID_TOKEN => [ @@ -387,7 +387,7 @@ return [ ], Exception::PROJECT_PROVIDER_DISABLED => [ 'name' => Exception::PROJECT_PROVIDER_DISABLED, - 'description' => 'The chosen OAuth provider is disabled. Please contact your project administrator for more information.', + 'description' => 'The chosen OAuth provider is disabled. You can enable the OAuth provider using the Appwrite console.', 'code' => 412, ], Exception::PROJECT_PROVIDER_UNSUPPORTED => [ From 5fee7378ad1883fa0b9693313b07f63574cba512 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Sun, 13 Feb 2022 13:12:16 +0400 Subject: [PATCH 93/95] feat: add test for error message --- app/config/errors.php | 5 +++++ app/controllers/general.php | 19 +++++++++++++++---- src/Appwrite/Extend/Exception.php | 1 + tests/e2e/General/HTTPTest.php | 3 ++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 6398ac808d..e0ebf3c6cf 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -58,6 +58,11 @@ return [ 'description' => 'The query\'s syntax is invalid. Please check the query and try again.', 'code' => 400, ], + Exception::GENERAL_ROUTE_NOT_FOUND => [ + 'name' => Exception::GENERAL_ROUTE_NOT_FOUND, + 'description' => 'The requested route was not found. Please refer to the docs and try again.', + 'code' => 404, + ], Exception::GENERAL_CURSOR_NOT_FOUND => [ 'name' => Exception::GENERAL_CURSOR_NOT_FOUND, 'description' => 'The cursor is invalid. This can happen if the item represented by the cursor has been deleted.', diff --git a/app/controllers/general.php b/app/controllers/general.php index 55517fff93..37be00f0f9 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -375,14 +375,25 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l throw $error; } + + /** Handle Utopia Errors */ + if ($error instanceof Utopia\Exception) { + $code = $error->getCode(); + $error = new Exception($error->getMessage(), $code, Exception::GENERAL_UNKNOWN, $error); + switch($code) { + case 400: + $error->setType(Exception::GENERAL_ARGUMENT_INVALID); + break; + case 404: + $error->setType(Exception::GENERAL_ROUTE_NOT_FOUND); + break; + } + } + /** Wrap all exceptions inside Appwrite\Extend\Exception */ if (!($error instanceof Exception)) { $error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_UNKNOWN, $error); } - - if ($error instanceof Utopia\Exception && $error->getCode() === 400) { - $error->setType(Exception::GENERAL_ARGUMENT_INVALID); - } $template = ($route) ? $route->getLabel('error', null) : null; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 5b05551b43..71b2ff95d4 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -42,6 +42,7 @@ class Exception extends \Exception const GENERAL_ARGUMENT_INVALID = 'general_argument_invalid'; const GENERAL_QUERY_LIMIT_EXCEEDED = 'general_query_limit_exceeded'; const GENERAL_QUERY_INVALID = 'general_query_invalid'; + const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found'; const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found'; const GENERAL_SERVER_ERROR = 'general_server_error'; diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index 4b26f2fcd9..696c3a3201 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -2,7 +2,7 @@ namespace Tests\E2E\General; -use Exception; +use Appwrite\Extend\Exception; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectNone; use Tests\E2E\Scopes\Scope; @@ -45,6 +45,7 @@ class HTTPTest extends Scope $this->assertEquals(404, $response['headers']['status-code']); $this->assertEquals('Not Found', $response['body']['message']); + $this->assertEquals(Exception::GENERAL_ROUTE_NOT_FOUND, $response['body']['type']); $this->assertEquals(404, $response['body']['code']); $this->assertEquals('dev', $response['body']['version']); } From ca2cf23a74278c6dcba504f116bb076013f47fd1 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Wed, 16 Feb 2022 19:28:37 +0400 Subject: [PATCH 94/95] feat: support mock endpoints --- app/config/errors.php | 5 ++++ app/controllers/mock.php | 43 ++++++++++++++++--------------- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index e0ebf3c6cf..a773888048 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -13,6 +13,11 @@ return [ 'description' => 'An unknown error has occured. Please check the logs for more information.', 'code' => 500, ], + Exception::GENERAL_MOCK => [ + 'name' => Exception::GENERAL_MOCK, + 'description' => 'General errors thrown by the mock controller used for testing.', + 'code' => 400, + ], Exception::GENERAL_ACCESS_FORBIDDEN => [ 'name' => Exception::GENERAL_ACCESS_FORBIDDEN, 'description' => 'Access to this API is forbidden.', diff --git a/app/controllers/mock.php b/app/controllers/mock.php index ea437bf3c5..a45bdf641e 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -2,6 +2,7 @@ global $utopia, $request, $response; +use Appwrite\Extend\Exception; use Utopia\Database\Document; use Appwrite\Network\Validator\Host; use Appwrite\Utopia\Response; @@ -251,32 +252,32 @@ App::post('/v1/mock/tests/general/upload') $file['size'] = (\is_array($file['size'])) ? $file['size'] : [$file['size']]; if(is_null($start) || is_null($end) || is_null($size)) { - throw new Exception('Invalid content-range header', 400); + throw new Exception('Invalid content-range header', 400, Exception::GENERAL_MOCK); } if($start > $end || $end > $size) { - throw new Exception('Invalid content-range header', 400); + throw new Exception('Invalid content-range header', 400, Exception::GENERAL_MOCK); } if($start === 0 && !empty($id)) { - throw new Exception('First chunked request cannot have id header', 400); + throw new Exception('First chunked request cannot have id header', 400, Exception::GENERAL_MOCK); } if($start !== 0 && $id !== 'newfileid') { - throw new Exception('All chunked request must have id header (except first)', 400); + throw new Exception('All chunked request must have id header (except first)', 400, Exception::GENERAL_MOCK); } if($end !== $size && $end-$start+1 !== 5*1024*1024) { - throw new Exception('Chunk size must be 5MB (except last chunk)', 400); + throw new Exception('Chunk size must be 5MB (except last chunk)', 400, Exception::GENERAL_MOCK); } foreach ($file['size'] as $i => $sz) { if ($end !== $size && $sz !== 5*1024*1024) { - throw new Exception('Wrong chunk size', 400); + throw new Exception('Wrong chunk size', 400, Exception::GENERAL_MOCK); } if($sz > 5*1024*1024) { - throw new Exception('Chunk size must be 5MB or less', 400); + throw new Exception('Chunk size must be 5MB or less', 400, Exception::GENERAL_MOCK); } } if($end !== $size) { @@ -289,19 +290,19 @@ App::post('/v1/mock/tests/general/upload') foreach ($file['name'] as $i => $name) { if ($name !== 'file.png') { - throw new Exception('Wrong file name', 400); + throw new Exception('Wrong file name', 400, Exception::GENERAL_MOCK); } } foreach ($file['size'] as $i => $size) { if ($size !== 38756) { - throw new Exception('Wrong file size', 400); + throw new Exception('Wrong file size', 400, Exception::GENERAL_MOCK); } } foreach ($file['tmp_name'] as $i => $tmpName) { if (\md5(\file_get_contents($tmpName)) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') { - throw new Exception('Wrong file uploaded', 400); + throw new Exception('Wrong file uploaded', 400, Exception::GENERAL_MOCK); } } } @@ -379,7 +380,7 @@ App::get('/v1/mock/tests/general/get-cookie') /** @var Appwrite\Utopia\Request $request */ if ($request->getCookie('cookieName', '') !== 'cookieValue') { - throw new Exception('Missing cookie value', 400); + throw new Exception('Missing cookie value', 400, Exception::GENERAL_MOCK); } }); @@ -414,7 +415,7 @@ App::get('/v1/mock/tests/general/400-error') ->label('sdk.response.model', Response::MODEL_ERROR) ->label('sdk.mock', true) ->action(function () { - throw new Exception('Mock 400 error', 400); + throw new Exception('Mock 400 error', 400, Exception::GENERAL_MOCK); }); App::get('/v1/mock/tests/general/500-error') @@ -430,7 +431,7 @@ App::get('/v1/mock/tests/general/500-error') ->label('sdk.response.model', Response::MODEL_ERROR) ->label('sdk.mock', true) ->action(function () { - throw new Exception('Mock 500 error', 500); + throw new Exception('Mock 500 error', 500, Exception::GENERAL_MOCK); }); App::get('/v1/mock/tests/general/502-error') @@ -489,11 +490,11 @@ App::get('/v1/mock/tests/general/oauth2/token') /** @var Appwrite\Utopia\Response $response */ if ($client_id != '1') { - throw new Exception('Invalid client ID'); + throw new Exception('Invalid client ID', 400, Exception::GENERAL_MOCK); } if ($client_secret != '123456') { - throw new Exception('Invalid client secret'); + throw new Exception('Invalid client secret', 400, Exception::GENERAL_MOCK); } $responseJson = [ @@ -504,18 +505,18 @@ App::get('/v1/mock/tests/general/oauth2/token') if($grantType === 'authorization_code') { if ($code !== 'abcdef') { - throw new Exception('Invalid token'); + throw new Exception('Invalid token', 400, Exception::GENERAL_MOCK); } $response->json($responseJson); } else if($grantType === 'refresh_token') { if ($refreshToken !== 'tuvwxyz') { - throw new Exception('Invalid refresh token'); + throw new Exception('Invalid refresh token', 400, Exception::GENERAL_MOCK); } $response->json($responseJson); } else { - throw new Exception('Invalid grant type'); + throw new Exception('Invalid grant type', 400, Exception::GENERAL_MOCK); } }); @@ -530,7 +531,7 @@ App::get('/v1/mock/tests/general/oauth2/user') /** @var Appwrite\Utopia\Response $response */ if ($token != '123456') { - throw new Exception('Invalid token'); + throw new Exception('Invalid token', 400, Exception::GENERAL_MOCK); } $response->json([ @@ -581,7 +582,7 @@ App::shutdown(function($utopia, $response, $request) { $tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : []; if (!\is_array($tests)) { - throw new Exception('Failed to read results', 500); + throw new Exception('Failed to read results', 500, Exception::GENERAL_MOCK); } $result[$route->getMethod() . ':' . $route->getPath()] = true; @@ -589,7 +590,7 @@ App::shutdown(function($utopia, $response, $request) { $tests = \array_merge($tests, $result); if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) { - throw new Exception('Failed to save results', 500); + throw new Exception('Failed to save results', 500, Exception::GENERAL_MOCK); } $response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK); diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 71b2ff95d4..ed485eff8d 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -33,6 +33,7 @@ class Exception extends \Exception /** General */ const GENERAL_UNKNOWN = 'general_unknown'; + const GENERAL_MOCK = 'general_mock'; const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden'; const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin'; const GENERAL_SERVICE_DISABLED = 'general_service_disabled'; From ca2bee015aca827801421e5c9289218fd2e9f291 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Thu, 17 Feb 2022 02:55:54 +0400 Subject: [PATCH 95/95] feat: add new error codes for storage --- app/config/errors.php | 23 ++++++-- app/controllers/api/storage.php | 96 +++++++++++++++---------------- src/Appwrite/Extend/Exception.php | 5 +- 3 files changed, 71 insertions(+), 53 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 4e099a36cc..6d7c9544db 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -259,15 +259,30 @@ return [ 'description' => 'The file size is either not valid or exceeds the maximum allowed size. Please check the file or the value of the _APP_STORAGE_LIMIT environment variable.', 'code' => 400, ], + Exception::STORAGE_INVALID_FILE => [ + 'name' => Exception::STORAGE_INVALID_FILE, + 'description' => 'The uploaded file is invalid. Please check the file and try again.', + 'code' => 403, + ], + Exception::STORAGE_BUCKET_ALREADY_EXISTS => [ + 'name' => Exception::STORAGE_BUCKET_ALREADY_EXISTS, + 'description' => 'A storage bucket with the requested ID already exists.', + 'code' => 409, + ], + Exception::STORAGE_BUCKET_NOT_FOUND => [ + 'name' => Exception::STORAGE_BUCKET_NOT_FOUND, + 'description' => 'Storage bucket with the requested ID could not be found.', + 'code' => 404, + ], Exception::STORAGE_INVALID_CONTENT_RANGE => [ 'name' => Exception::STORAGE_INVALID_CONTENT_RANGE, 'description' => 'The content range is invalid. Please check the value of the Content-Range header.', 'code' => 400, ], - Exception::STORAGE_INVALID_FILE => [ - 'name' => Exception::STORAGE_INVALID_FILE, - 'description' => 'The uploaded file is invalid. Please check the file and try again.', - 'code' => 403, + Exception::STORAGE_INVALID_RANGE => [ + 'name' => Exception::STORAGE_INVALID_RANGE, + 'description' => 'The requested range is not satisfiable. Please check the value of the Range header.', + 'code' => 416, ], /** Functions */ diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 31af60121f..691c870c9b 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -71,7 +71,7 @@ App::post('/v1/storage/buckets') try { $files = Config::getParam('collections', [])['files'] ?? []; if (empty($files)) { - throw new Exception('Files collection is not configured.'); + throw new Exception('Files collection is not configured.', 500, Exception::GENERAL_SERVER_ERROR); } $attributes = []; @@ -118,7 +118,7 @@ App::post('/v1/storage/buckets') 'search' => implode(' ', [$bucketId, $name]), ])); } catch (Duplicate $th) { - throw new Exception('Bucket already exists', 409); + throw new Exception('Bucket already exists', 409, Exception::STORAGE_BUCKET_ALREADY_EXISTS); } $audits @@ -164,7 +164,7 @@ App::get('/v1/storage/buckets') $cursorBucket = $dbForProject->getDocument('buckets', $cursor); if ($cursorBucket->isEmpty()) { - throw new Exception("Bucket '{$cursor}' for the 'cursor' value not found.", 400); + throw new Exception("Bucket '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND); } } @@ -199,7 +199,7 @@ App::get('/v1/storage/buckets/:bucketId') $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } $usage->setParam('storage.buckets.read', 1); @@ -242,7 +242,7 @@ App::put('/v1/storage/buckets/:bucketId') $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } $read??=$bucket->getAttribute('$read', []); // By default inherit read permissions @@ -305,11 +305,11 @@ App::delete('/v1/storage/buckets/:bucketId') $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } if (!$dbForProject->deleteDocument('buckets', $bucketId)) { - throw new Exception('Failed to remove project from DB', 500); + throw new Exception('Failed to remove project from DB', 500, Exception::GENERAL_SERVER_ERROR); } $deletes @@ -378,7 +378,7 @@ App::post('/v1/storage/buckets/:bucketId/files') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced @@ -386,7 +386,7 @@ App::post('/v1/storage/buckets/:bucketId/files') if ($permissionBucket) { $validator = new Authorization('write'); if (!$validator->isValid($bucket->getWrite())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -419,12 +419,12 @@ App::post('/v1/storage/buckets/:bucketId/files') $maximumFileSize = $bucket->getAttribute('maximumFileSize', 0); if ($maximumFileSize > (int) App::getEnv('_APP_STORAGE_LIMIT', 0)) { - throw new Exception('Error bucket maximum file size is larger than _APP_STORAGE_LIMIT', 500); + throw new Exception('Error bucket maximum file size is larger than _APP_STORAGE_LIMIT', 500, Exception::GENERAL_SERVER_ERROR); } $file = $request->getFiles('file'); if (empty($file)) { - throw new Exception('No file sent', 400); + throw new Exception('No file sent', 400, Exception::STORAGE_FILE_EMPTY); } // Make sure we handle a single file and multiple files the same way @@ -443,7 +443,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $fileSize = $request->getContentRangeSize(); $fileId = $request->getHeader('x-appwrite-id', $fileId); if (is_null($start) || is_null($end) || is_null($fileSize)) { - throw new Exception('Invalid content-range header', 400); + throw new Exception('Invalid content-range header', 400, Exception::STORAGE_INVALID_CONTENT_RANGE); } if ($end === $fileSize) { @@ -463,7 +463,7 @@ App::post('/v1/storage/buckets/:bucketId/files') $allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []); $fileExt = new FileExt($allowedFileExtensions); if (!empty($allowedFileExtensions) && !$fileExt->isValid($fileName)) { - throw new Exception('File extension not allowed', 400); + throw new Exception('File extension not allowed', 400, Exception::STORAGE_FILE_TYPE_UNSUPPORTED); } // Check if file size is exceeding allowed limit @@ -537,7 +537,7 @@ App::post('/v1/storage/buckets/:bucketId/files') if (!empty($data)) { if (!$deviceFiles->write($path, $data, $mimeType)) { - throw new Exception('Failed to save file', 500); + throw new Exception('Failed to save file', 500, Exception::GENERAL_SERVER_ERROR); } } @@ -610,9 +610,9 @@ App::post('/v1/storage/buckets/:bucketId/files') } } catch (StructureException $exception) { - throw new Exception($exception->getMessage(), 400); + throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } catch (DuplicateException $exception) { - throw new Exception('Document already exists', 409); + throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } $audits @@ -669,9 +669,9 @@ App::post('/v1/storage/buckets/:bucketId/files') } } } catch (StructureException $exception) { - throw new Exception($exception->getMessage(), 400); + throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE); } catch (DuplicateException $exception) { - throw new Exception('Document already exists', 409); + throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS); } } @@ -717,14 +717,14 @@ App::get('/v1/storage/buckets/:bucketId/files') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('read'); if (!$validator->isValid($bucket->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -801,14 +801,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('read'); if (!$validator->isValid($bucket->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -821,7 +821,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId') } if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $usage ->setParam('storage.files.read', 1) @@ -878,14 +878,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('read'); if (!$validator->isValid($bucket->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::STORAGE_BUCKET_NOT_FOUND); } } @@ -910,7 +910,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') } if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $path = $file->getAttribute('path'); @@ -938,7 +938,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $compressor = new GZIP(); if (!$deviceFiles->exists($path)) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $cache = new Cache(new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId() . DIRECTORY_SEPARATOR . $bucketId . DIRECTORY_SEPARATOR . $fileId)); // Limit file number or size @@ -1049,14 +1049,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('read'); if (!$validator->isValid($bucket->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1069,13 +1069,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') } if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $path = $file->getAttribute('path', ''); if (!$deviceFiles->exists($path)) { - throw new Exception('File not found in ' . $path, 404); + throw new Exception('File not found in ' . $path, 404, Exception::STORAGE_FILE_NOT_FOUND); } $usage @@ -1103,7 +1103,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') } if ($unit !== 'bytes' || $start >= $end || $end >= $size) { - throw new Exception('Invalid range', 416); + throw new Exception('Invalid range', 416, Exception::STORAGE_INVALID_RANGE); } $response @@ -1194,14 +1194,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('read'); if (!$validator->isValid($bucket->getRead())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1216,13 +1216,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $mimes = Config::getParam('storage-mimes'); if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $path = $file->getAttribute('path', ''); if (!$deviceFiles->exists($path)) { - throw new Exception('File not found in ' . $path, 404); + throw new Exception('File not found in ' . $path, 404, Exception::STORAGE_FILE_NOT_FOUND); } $compressor = new GZIP(); @@ -1255,7 +1255,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') } if ($unit != 'bytes' || $start >= $end || $end >= $size) { - throw new Exception('Invalid range', 416); + throw new Exception('Invalid range', 416, Exception::STORAGE_INVALID_RANGE); } $response @@ -1363,26 +1363,26 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) { foreach ($read as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400); + throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED); } } foreach ($write as $role) { if (!Authorization::isRole($role)) { - throw new Exception('Write permissions must be one of: (' . \implode(', ', $roles) . ')', 400); + throw new Exception('Write permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED); } } } if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('write'); if (!$validator->isValid($bucket->getWrite())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1395,7 +1395,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') } if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } if ($bucket->getAttribute('permission') === 'bucket') { @@ -1463,14 +1463,14 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } // Check bucket permissions when enforced if ($bucket->getAttribute('permission') === 'bucket') { $validator = new Authorization('write'); if (!$validator->isValid($bucket->getWrite())) { - throw new Exception('Unauthorized permissions', 401); + throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED); } } @@ -1483,7 +1483,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') } if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) { - throw new Exception('File not found', 404); + throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND); } $deviceDeleted = false; @@ -1510,10 +1510,10 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') $deleted = $dbForProject->deleteDocument('bucket_' . $bucketId, $fileId); } if (!$deleted) { - throw new Exception('Failed to remove file from DB', 500); + throw new Exception('Failed to remove file from DB', 500, Exception::GENERAL_SERVER_ERROR); } } else { - throw new Exception('Failed to delete file from device', 500); + throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR); } $audits @@ -1667,7 +1667,7 @@ App::get('/v1/storage/:bucketId/usage') $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { - throw new Exception('Bucket not found', 404); + throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND); } $usage = []; diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index a9ae02a494..c39606fdd3 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -90,8 +90,11 @@ class Exception extends \Exception const STORAGE_FILE_EMPTY = 'storage_file_empty'; const STORAGE_FILE_TYPE_UNSUPPORTED = 'storage_file_type_unsupported'; const STORAGE_INVALID_FILE_SIZE = 'storage_invalid_file_size'; - const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range'; const STORAGE_INVALID_FILE = 'storage_invalid_file'; + const STORAGE_BUCKET_ALREADY_EXISTS = 'storage_bucket_already_exists'; + const STORAGE_BUCKET_NOT_FOUND = 'storage_bucket_not_found'; + const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range'; + const STORAGE_INVALID_RANGE = 'storage_invalid_range'; /** Functions */ const FUNCTION_NOT_FOUND = 'function_not_found';