1
0
Fork 0
mirror of synced 2024-06-27 02:31:04 +12:00

Merge branch '0.13.x' of https://github.com/appwrite/appwrite into feat-storage-ui-updates

This commit is contained in:
Damodar Lohani 2022-02-17 10:33:39 +00:00
commit fc721ac22e
33 changed files with 1120 additions and 419 deletions

473
app/config/errors.php Normal file
View file

@ -0,0 +1,473 @@
<?php
/**
* List of server wide error codes and their respective messages.
*/
use Appwrite\Extend\Exception;
return [
/** General Errors */
Exception::GENERAL_UNKNOWN => [
'name' => Exception::GENERAL_UNKNOWN,
'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.',
'code' => 401,
],
Exception::GENERAL_UNKNOWN_ORIGIN => [
'name' => Exception::GENERAL_UNKNOWN_ORIGIN,
'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 => [
'name' => Exception::GENERAL_SERVICE_DISABLED,
'description' => 'The requested service is disabled. You can enable the service from the Appwrite console.',
'code' => 503,
],
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,
],
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::GENERAL_SMTP_DISABLED => [
'name' => Exception::GENERAL_SMTP_DISABLED,
'description' => 'SMTP is disabled on your Appwrite instance. You can <a href="/docs/email-delivery">learn more about setting up SMTP</a> in our docs.',
'code' => 503,
],
Exception::GENERAL_ARGUMENT_INVALID => [
'name' => Exception::GENERAL_ARGUMENT_INVALID,
'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_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.',
'code' => 400,
],
Exception::GENERAL_SERVER_ERROR => [
'name' => Exception::GENERAL_SERVER_ERROR,
'description' => 'An internal server error occurred.',
'code' => 500,
],
/** 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.',
'code' => 501,
],
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. You can unblock the user from the Appwrite console.',
'code' => 401,
],
Exception::USER_INVALID_TOKEN => [
'name' => Exception::USER_INVALID_TOKEN,
'description' => 'Invalid token passed in the request.',
'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.',
'code' => 401,
],
Exception::USER_INVALID_CREDENTIALS => [
'name' => Exception::USER_INVALID_CREDENTIALS,
'description' => 'Invalid credentials. Please check the email and password.',
'code' => 401,
],
Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED => [
'name' => Exception::USER_ANONYMOUS_CONSOLE_PROHIBITED,
'description' => 'Anonymous users cannot be created for the console project.',
'code' => 401,
],
Exception::USER_SESSION_ALREADY_EXISTS => [
'name' => Exception::USER_SESSION_ALREADY_EXISTS,
'description' => 'Creation of anonymous users is prohibited when a session is active.',
'code' => 401,
],
Exception::USER_NOT_FOUND => [
'name' => Exception::USER_NOT_FOUND,
'description' => 'User with the requested ID could not be found.',
'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.',
'code' => 409,
],
Exception::USER_PASSWORD_MISMATCH => [
'name' => Exception::USER_PASSWORD_MISMATCH,
'description' => 'Passwords do not match. Please check the password and confirm password.',
'code' => 400,
],
Exception::USER_SESSION_NOT_FOUND => [
'name' => Exception::USER_SESSION_NOT_FOUND,
'description' => 'The current user session could not be found.',
'code' => 404,
],
Exception::USER_UNAUTHORIZED => [
'name' => Exception::USER_UNAUTHORIZED,
'description' => 'The current user is not authorized to perform the requested action.',
'code' => 401,
],
Exception::USER_AUTH_METHOD_UNSUPPORTED => [
'name' => Exception::USER_AUTH_METHOD_UNSUPPORTED,
'description' => 'The requested authentication method is either disabled or unsupported. Please check the supported authentication methods in the Appwrite console.',
'code' => 501,
],
/** Teams */
Exception::TEAM_NOT_FOUND => [
'name' => Exception::TEAM_NOT_FOUND,
'description' => 'Team with the requested ID could not be found.',
'code' => 404,
],
Exception::TEAM_INVITE_ALREADY_EXISTS => [
'name' => Exception::TEAM_INVITE_ALREADY_EXISTS,
'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 team invitation could not be found.',
'code' => 404,
],
Exception::TEAM_INVALID_SECRET => [
'name' => Exception::TEAM_INVALID_SECRET,
'description' => 'The team invitation secret is invalid.',
'code' => 401,
],
Exception::TEAM_MEMBERSHIP_MISMATCH => [
'name' => Exception::TEAM_MEMBERSHIP_MISMATCH,
'description' => 'The membership ID does not belong to the team ID.',
'code' => 404,
],
Exception::TEAM_INVITE_MISMATCH => [
'name' => Exception::TEAM_INVITE_MISMATCH,
'description' => 'The invite does not belong to the current user.',
'code' => 401,
],
/** Membership */
Exception::MEMBERSHIP_NOT_FOUND => [
'name' => Exception::MEMBERSHIP_NOT_FOUND,
'description' => 'Membership with the requested ID could not be found.',
'code' => 404,
],
/** Avatars */
Exception::AVATAR_SET_NOT_FOUND => [
'name' => Exception::AVATAR_SET_NOT_FOUND,
'description' => 'The requested avatar set could not be found.',
'code' => 404
],
Exception::AVATAR_NOT_FOUND => [
'name' => Exception::AVATAR_NOT_FOUND,
'description' => 'The request avatar could not be found.',
'code' => 404,
],
Exception::AVATAR_IMAGE_NOT_FOUND => [
'name' => Exception::AVATAR_IMAGE_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' => 'Failed to fetch favicon from the requested URL.',
'code' => 404,
],
Exception::AVATAR_ICON_NOT_FOUND => [
'name' => Exception::AVATAR_ICON_NOT_FOUND,
'description' => 'The requested favicon could not be found.',
'code' => 404,
],
/** Storage */
Exception::STORAGE_FILE_NOT_FOUND => [
'name' => Exception::STORAGE_FILE_NOT_FOUND,
'description' => 'The requested file could not be found.',
'code' => 404,
],
Exception::STORAGE_DEVICE_NOT_FOUND => [
'name' => Exception::STORAGE_DEVICE_NOT_FOUND,
'description' => 'The requested storage device could not be found.',
'code' => 400,
],
Exception::STORAGE_FILE_EMPTY => [
'name' => Exception::STORAGE_FILE_EMPTY,
'description' => 'Empty file passed to the endpoint.',
'code' => 400,
],
Exception::STORAGE_FILE_TYPE_UNSUPPORTED => [
'name' => Exception::STORAGE_FILE_TYPE_UNSUPPORTED,
'description' => 'The file type is not supported.',
'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. 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_RANGE => [
'name' => Exception::STORAGE_INVALID_RANGE,
'description' => 'The requested range is not satisfiable. Please check the value of the Range header.',
'code' => 416,
],
/** Functions */
Exception::FUNCTION_NOT_FOUND => [
'name' => Exception::FUNCTION_NOT_FOUND,
'description' => 'Function with the requested ID could not be found.',
'code' => 404,
],
/** Deployments */
Exception::DEPLOYMENT_NOT_FOUND => [
'name' => Exception::DEPLOYMENT_NOT_FOUND,
'description' => 'Deployment with the requested ID could not be found.',
'code' => 404,
],
/** Executions */
Exception::EXECUTION_NOT_FOUND => [
'name' => Exception::EXECUTION_NOT_FOUND,
'description' => 'Execution with the requested ID could not be found.',
'code' => 404,
],
/** Collections */
Exception::COLLECTION_NOT_FOUND => [
'name' => Exception::COLLECTION_NOT_FOUND,
'description' => 'Collection with the requested ID could not be found.',
'code' => 404,
],
Exception::COLLECTION_ALREADY_EXISTS => [
'name' => Exception::COLLECTION_ALREADY_EXISTS,
'description' => 'A collection with the requested ID already exists.',
'code' => 409,
],
Exception::COLLECTION_LIMIT_EXCEEDED => [
'name' => Exception::COLLECTION_LIMIT_EXCEEDED,
'description' => 'The maximum number of collections has been reached.',
'code' => 400,
],
/** Documents */
Exception::DOCUMENT_NOT_FOUND => [
'name' => Exception::DOCUMENT_NOT_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. Please ensure the attributes match the collection definition.',
'code' => 400,
],
Exception::DOCUMENT_MISSING_PAYLOAD => [
'name' => Exception::DOCUMENT_MISSING_PAYLOAD,
'description' => 'The document payload is missing.',
'code' => 400,
],
Exception::DOCUMENT_ALREADY_EXISTS => [
'name' => Exception::DOCUMENT_ALREADY_EXISTS,
'description' => 'Document with the requested ID already exists.',
'code' => 409,
],
/** Attributes */
Exception::ATTRIBUTE_NOT_FOUND => [
'name' => Exception::ATTRIBUTE_NOT_FOUND,
'description' => 'Attribute with the requested ID could not be found.',
'code' => 404,
],
Exception::ATTRIBUTE_UNKNOWN => [
'name' => Exception::ATTRIBUTE_UNKNOWN,
'description' => 'The attribute required for the index could not be found. Please confirm all your attributes are in the <span class="tag">available</span> state.',
'code' => 400,
],
Exception::ATTRIBUTE_NOT_AVAILABLE => [
'name' => Exception::ATTRIBUTE_NOT_AVAILABLE,
'description' => 'The requested attribute is not yet <span class="tag">available</span>. Please try again later.',
'code' => 400,
],
Exception::ATTRIBUTE_FORMAT_UNSUPPORTED => [
'name' => Exception::ATTRIBUTE_FORMAT_UNSUPPORTED,
'description' => 'The requested attribute format is not supported.',
'code' => 400,
],
Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED => [
'name' => Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED,
'description' => 'Default values cannot be set for <span class="tag">array</span> and <span class="tag">required</span> attributes.',
'code' => 400,
],
Exception::ATTRIBUTE_ALREADY_EXISTS => [
'name' => Exception::ATTRIBUTE_ALREADY_EXISTS,
'description' => 'Attribute with the requested ID already exists.',
'code' => 409,
],
Exception::ATTRIBUTE_LIMIT_EXCEEDED => [
'name' => Exception::ATTRIBUTE_LIMIT_EXCEEDED,
'description' => 'The maximum number of attributes has been reached.',
'code' => 400,
],
Exception::ATTRIBUTE_VALUE_INVALID => [
'name' => Exception::ATTRIBUTE_VALUE_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' => 'Index with the requested ID could not be found.',
'code' => 404,
],
Exception::INDEX_LIMIT_EXCEEDED => [
'name' => Exception::INDEX_LIMIT_EXCEEDED,
'description' => 'The maximum number of indexes has been reached.',
'code' => 400,
],
Exception::INDEX_ALREADY_EXISTS => [
'name' => Exception::INDEX_ALREADY_EXISTS,
'description' => 'Index with the requested ID already exists.',
'code' => 409,
],
/** Project Errors */
Exception::PROJECT_NOT_FOUND => [
'name' => Exception::PROJECT_NOT_FOUND,
'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 => [
'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::PROJECT_PROVIDER_DISABLED => [
'name' => Exception::PROJECT_PROVIDER_DISABLED,
'description' => 'The chosen OAuth provider is disabled. You can enable the OAuth provider using the Appwrite console.',
'code' => 412,
],
Exception::PROJECT_PROVIDER_UNSUPPORTED => [
'name' => Exception::PROJECT_PROVIDER_UNSUPPORTED,
'description' => 'The chosen OAuth provider is unsupported. Please check <a href="/docs/client/account?sdk=web-default#accountCreateOAuth2Session"> the docs</a> 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.',
'code' => 404,
],
Exception::KEY_NOT_FOUND => [
'name' => Exception::KEY_NOT_FOUND,
'description' => 'Key with the requested ID could not be found.',
'code' => 404,
],
Exception::PLATFORM_NOT_FOUND => [
'name' => Exception::PLATFORM_NOT_FOUND,
'description' => 'Platform with the requested ID could not be found.',
'code' => 404,
],
Exception::DOMAIN_NOT_FOUND => [
'name' => Exception::DOMAIN_NOT_FOUND,
'description' => 'Domain with the requested ID could not be found.',
'code' => 404,
],
Exception::DOMAIN_ALREADY_EXISTS => [
'name' => Exception::DOMAIN_ALREADY_EXISTS,
'description' => 'A Domain with the requested ID already exists.',
'code' => 409,
],
Exception::DOMAIN_VERIFICATION_FAILED => [
'name' => Exception::DOMAIN_VERIFICATION_FAILED,
'description' => 'Domain verification for the requested domain has failed.',
'code' => 401,
]
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,7 @@
return [ // Based on this list @see http://stackoverflow.com/a/4212908/2299554
'default' => __DIR__.'/logos/none.png',
'default_image' => __DIR__.'/logos/image.png',
// Video Files
'video/mp4' => __DIR__.'/logos/video.png',

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -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\Boolean;
@ -69,11 +69,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::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);
throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401, Exception::USER_IP_NOT_WHITELISTED);
}
}
@ -85,7 +85,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::USER_COUNT_EXCEEDED);
}
}
@ -111,7 +111,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::USER_ALREADY_EXISTS);
}
Authorization::unsetRole('role:' . Auth::USER_ROLE_GUEST);
@ -176,11 +176,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::USER_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::USER_BLOCKED); // User is in status blocked
}
$detector = new Detector($request->getUserAgent('UNKNOWN'));
@ -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);
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);
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);
throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED);
}
$oauth2 = new $className($appId, $appSecret, $callback);
@ -416,18 +416,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::GENERAL_SERVER_ERROR);
}
} 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::PROJECT_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::PROJECT_INVALID_FAILURE_URL);
}
$state['failure'] = null;
@ -441,7 +441,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::GENERAL_SERVER_ERROR);
}
$oauth2ID = $oauth2->getUserID($accessToken);
@ -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);
throw new Exception('Missing ID from OAuth2 provider', 400, Exception::PROJECT_MISSING_USER_ID);
}
$sessions = $user->getAttribute('sessions', []);
@ -486,7 +486,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::USER_COUNT_EXCEEDED);
}
}
@ -512,13 +512,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::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::USER_BLOCKED); // User is in status blocked
}
// Create session token, verify user account and update OAuth2 ID and Access Token
@ -643,7 +643,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::GENERAL_SMTP_DISABLED);
}
$roles = Authorization::getRoles();
@ -661,7 +661,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::USER_COUNT_EXCEEDED);
}
}
@ -711,7 +711,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::GENERAL_SERVER_ERROR);
}
if(empty($url)) {
@ -789,13 +789,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::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::USER_INVALID_TOKEN);
}
$detector = new Detector($request->getUserAgent('UNKNOWN'));
@ -845,7 +845,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::GENERAL_SERVER_ERROR);
}
$audits
@ -918,11 +918,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);
throw new Exception('Cannot create an anonymous user when logged in.', 401, Exception::USER_SESSION_ALREADY_EXISTS);
}
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
@ -933,7 +933,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::USER_COUNT_EXCEEDED);
}
}
@ -1057,7 +1057,7 @@ App::post('/v1/account/jwt')
}
if ($current->isEmpty()) {
throw new Exception('No valid session found', 401);
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.
@ -1303,7 +1303,7 @@ App::get('/v1/account/sessions/:sessionId')
}
}
throw new Exception('Session not found', 404);
throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND);
});
App::patch('/v1/account/name')
@ -1377,7 +1377,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::USER_INVALID_CREDENTIALS);
}
$user = $dbForProject->updateDocument('users', $user->getId(), $user
@ -1429,14 +1429,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::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);
throw new Exception('User already registered', 409, Exception::USER_ALREADY_EXISTS);
}
try {
@ -1447,7 +1447,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::USER_EMAIL_ALREADY_EXISTS);
}
$audits
@ -1651,7 +1651,7 @@ App::delete('/v1/account/sessions/:sessionId')
}
}
throw new Exception('Session not found', 404);
throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND);
});
App::patch('/v1/account/sessions/:sessionId')
@ -1873,7 +1873,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::GENERAL_SMTP_DISABLED);
}
$roles = Authorization::getRoles();
@ -1884,11 +1884,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::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::USER_BLOCKED);
}
$expire = \time() + Auth::TOKEN_EXPIRATION_RECOVERY;
@ -1979,20 +1979,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::USER_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::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::USER_INVALID_TOKEN);
}
Authorization::setRole('user:' . $profile->getId());
@ -2066,7 +2066,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::GENERAL_SMTP_DISABLED);
}
$roles = Authorization::getRoles();
@ -2164,14 +2164,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::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::USER_INVALID_TOKEN);
}
Authorization::setRole('user:' . $profile->getId());

View file

@ -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::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);
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,19 +169,19 @@ 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::GENERAL_SERVER_ERROR);
}
$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 {
$image = new Image($fetch);
} catch (\Exception$exception) {
throw new Exception('Unable to parse image', 500);
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);
throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR);
}
$curl = \curl_init();
@ -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();
@ -317,7 +317,7 @@ App::get('/v1/avatars/favicon')
$data = @\file_get_contents($outputHref, false);
if (empty($data) || (\mb_substr($data, 0, 5) === '<html') || \mb_substr($data, 0, 5) === '<!doc') {
throw new Exception('Favicon not found', 404);
throw new Exception('Favicon not found', 404, Exception::AVATAR_ICON_NOT_FOUND);
}
$cache->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);

View file

@ -1,7 +1,7 @@
<?php
use Utopia\App;
use Utopia\Exception;
use Appwrite\Extend\Exception;
use Utopia\Audit\Audit;
use Utopia\Validator\Boolean;
use Utopia\Validator\FloatValidator;
@ -65,22 +65,22 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
$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 (!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::GENERAL_CURSOR_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::GENERAL_SERVER_ERROR);
}
$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,13 @@ 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);
// TODO: Isn't this a 401: Unauthorized Error ?
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);
throw new Exception('Write permissions must be one of: ('.\implode(', ', $roles).')', 400, Exception::USER_UNAUTHORIZED);
}
}
}
@ -1648,10 +1649,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 +1710,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 +1718,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 +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);
throw new Exception("You cannot use more than 100 query values on attribute '{$query->getAttribute()}'", 400, Exception::GENERAL_QUERY_LIMIT_EXCEEDED);
}
return $query;
@ -1734,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);
throw new Exception($validator->getDescription(), 400, Exception::GENERAL_QUERY_INVALID);
}
}
@ -1745,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);
throw new Exception("Document '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND);
}
}
@ -1803,7 +1804,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 +1812,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 +1829,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 +1869,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 +1970,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 +1978,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 +1988,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);
@ -2014,14 +2015,14 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
if(!is_null($read)) {
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::USER_UNAUTHORIZED);
}
}
}
if(!is_null($write)) {
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::USER_UNAUTHORIZED);
}
}
}
@ -2040,13 +2041,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());
@ -2101,7 +2102,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);
}
}
@ -2109,7 +2110,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);
}
}
@ -2121,7 +2122,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') {

View file

@ -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::GENERAL_CURSOR_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::GENERAL_SERVER_ERROR);
}
$deletes
@ -465,7 +465,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');
@ -474,7 +474,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
@ -483,7 +483,7 @@ App::post('/v1/functions/:functionId/tags')
$fileSize = (\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);
}
$contentRange = $request->getHeader('content-range');
@ -497,7 +497,7 @@ App::post('/v1/functions/:functionId/tags')
$fileSize = $request->getContentRangeSize();
$tagId = $request->getHeader('x-appwrite-id', $tagId);
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) {
@ -511,11 +511,11 @@ App::post('/v1/functions/:functionId/tags')
}
if (!$fileSizeValidator->isValid($fileSize)) { // 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($fileTmpName)) {
throw new Exception('Invalid file', 403);
throw new Exception('Invalid file', 403, Exception::STORAGE_INVALID_FILE);
}
// Save to storage
@ -534,7 +534,7 @@ App::post('/v1/functions/:functionId/tags')
$chunksUploaded = $deviceFunctions->upload($fileTmpName, $path, $chunk, $chunks);
if (empty($chunksUploaded)) {
throw new Exception('Failed moving file', 500);
throw new Exception('Failed moving file', 500, Exception::GENERAL_SERVER_ERROR);
}
if($chunksUploaded === $chunks) {
@ -610,14 +610,15 @@ 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);
// TODO: Shouldn't this be a 404 error ?
throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND);
}
}
@ -660,17 +661,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);
@ -702,22 +703,22 @@ 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);
}
if ($deviceFunctions->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::GENERAL_SERVER_ERROR);
}
}
@ -764,23 +765,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();
@ -863,14 +864,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::GENERAL_CURSOR_NOT_FOUND);
}
}
@ -913,17 +914,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);

View file

@ -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::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);
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');
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');
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');
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);
throw new Exception('Antivirus is not available', 500, Exception::GENERAL_SERVER_ERROR);
}
}

View file

@ -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::GENERAL_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', []);
@ -175,7 +175,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::GENERAL_CURSOR_NOT_FOUND);
}
}
@ -214,7 +214,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);
@ -245,7 +245,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 = [];
@ -364,7 +364,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
@ -407,7 +407,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', []);
@ -441,7 +441,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', []);
@ -474,7 +474,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', []);
@ -512,7 +512,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', []);
@ -545,13 +545,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
@ -560,11 +560,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::GENERAL_SERVER_ERROR);
}
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::GENERAL_SERVER_ERROR);
}
$response->noContent();
@ -598,7 +598,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);
@ -644,7 +644,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', [
@ -678,7 +678,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', [
@ -687,7 +687,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);
@ -720,7 +720,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);
@ -731,7 +731,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
@ -770,7 +770,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', [
@ -779,7 +779,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());
@ -813,7 +813,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([
@ -854,7 +854,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', [
@ -888,7 +888,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', [
@ -897,7 +897,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);
@ -926,7 +926,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', [
@ -935,7 +935,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
@ -970,7 +970,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', [
@ -979,7 +979,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());
@ -1016,7 +1016,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([
@ -1061,7 +1061,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', [
@ -1095,7 +1095,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', [
@ -1104,7 +1104,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);
@ -1135,7 +1135,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', [
@ -1144,7 +1144,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
@ -1182,7 +1182,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', [
@ -1191,7 +1191,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);
@ -1224,7 +1224,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', [
@ -1233,13 +1233,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::GENERAL_SERVER_ERROR);
}
$domain = new Domain($domain);
@ -1285,7 +1285,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', [
@ -1319,7 +1319,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', [
@ -1328,7 +1328,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);
@ -1355,7 +1355,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', [
@ -1364,13 +1364,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::GENERAL_SERVER_ERROR);
}
if ($domain->getAttribute('verification') === true) {
@ -1380,7 +1380,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);
}
@ -1417,7 +1417,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', [
@ -1426,7 +1426,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());

View file

@ -18,7 +18,7 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Permissions;
use Utopia\Database\Validator\UID;
use Utopia\Exception;
use Appwrite\Extend\Exception;
use Utopia\Image\Image;
use Utopia\Storage\Compression\Algorithms\GZIP;
use Utopia\Storage\Device\Local;
@ -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
@ -358,15 +358,17 @@ App::post('/v1/storage/buckets/:bucketId/files')
->inject('user')
->inject('audits')
->inject('usage')
->inject('events')
->inject('mode')
->inject('deviceFiles')
->inject('deviceLocal')
->action(function ($bucketId, $fileId, $file, $read, $write, $request, $response, $dbForProject, $user, $audits, $usage, $mode, $deviceFiles, $deviceLocal) {
->action(function ($bucketId, $fileId, $file, $read, $write, $request, $response, $dbForProject, $user, $audits, $usage, $events, $mode, $deviceFiles, $deviceLocal) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $user */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
/** @var Utopia\Storage\Device $deviceFiles */
/** @var Utopia\Storage\Device $deviceLocal */
@ -376,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
@ -384,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);
}
}
@ -397,12 +399,12 @@ App::post('/v1/storage/buckets/:bucketId/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::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);
}
}
}
@ -417,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
@ -441,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) {
@ -455,24 +457,24 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
/**
* Validators
*/
* Validators
*/
// Check if file type is allowed
$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
$fileSizeValidator = new FileSize($maximumFileSize);
if (!$fileSizeValidator->isValid($fileSize)) {
throw new Exception('File size not allowed', 400);
throw new Exception('File size not allowed', 400, Exception::STORAGE_INVALID_FILE_SIZE);
}
$upload = new Upload();
if (!$upload->isValid($fileTmpName)) {
throw new Exception('Invalid file', 403);
throw new Exception('Invalid file', 403, Exception::STORAGE_INVALID_FILE);
}
// Save to storage
@ -499,7 +501,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
$chunksUploaded = $deviceFiles->upload($fileTmpName, $path, $chunk, $chunks, $metadata);
if (empty($chunksUploaded)) {
throw new Exception('Failed uploading file', 500);
throw new Exception('Failed uploading file', 500, Exception::GENERAL_SERVER_ERROR);
}
$read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? [];
@ -511,7 +513,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
if (!$antivirus->fileScan($path)) {
$deviceFiles->delete($path);
throw new Exception('Invalid file', 400);
throw new Exception('Invalid file', 400, Exception::STORAGE_INVALID_FILE);
}
}
@ -535,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);
}
}
@ -608,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
@ -667,12 +669,14 @@ 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);
}
}
$events->setParam('bucket', $bucket->getArrayCopy());
$metadata = null; // was causing leaks as it was passed by reference
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@ -713,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);
}
}
@ -740,7 +744,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
}
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::GENERAL_CURSOR_NOT_FOUND);
}
}
@ -797,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);
}
}
@ -817,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)
@ -867,21 +871,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
/** @var string $mode */
if (!\extension_loaded('imagick')) {
throw new Exception('Imagick extension is missing', 500);
throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR);
}
$bucket = $dbForProject->getDocument('buckets', $bucketId);
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);
}
}
@ -906,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');
@ -915,8 +919,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$cipher = $file->getAttribute('openSSLCipher');
$mime = $file->getAttribute('mimeType');
if (!\in_array($mime, $inputs)) {
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > APP_LIMIT_PREVIEW) {
if(!\in_array($mime, $inputs)) {
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
} else {
// it was an image but the file size exceeded the limit
$path = $fileLogos['default_image'];
}
$algorithm = null;
$cipher = null;
$background = (empty($background)) ? 'eceff1' : $background;
@ -924,10 +934,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$key = \md5($path . $width . $height . $gravity . $quality . $borderWidth . $borderColor . $borderRadius . $opacity . $rotation . $background . $output);
}
$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
@ -1038,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);
}
}
@ -1058,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
@ -1092,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
@ -1183,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);
}
}
@ -1205,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();
@ -1244,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
@ -1332,12 +1343,14 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->inject('audits')
->inject('usage')
->inject('mode')
->action(function ($bucketId, $fileId, $read, $write, $response, $dbForProject, $user, $audits, $usage, $mode) {
->inject('events')
->action(function ($bucketId, $fileId, $read, $write, $response, $dbForProject, $user, $audits, $usage, $mode, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $user */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Stats\Stats $usage */
/** @var Appwirte\Event\Event $events */
/** @var string $mode */
$bucket = $dbForProject->getDocument('buckets', $bucketId);
@ -1350,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);
}
}
@ -1382,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') {
@ -1399,6 +1412,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
);
}
$events->setParam('bucket', $bucket->getArrayCopy());
$audits
->setParam('event', 'storage.files.update')
->setParam('resource', 'file/' . $file->getId())
@ -1448,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);
}
}
@ -1468,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;
@ -1495,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
@ -1514,6 +1529,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
$events
->setParam('eventData', $response->output($file, Response::MODEL_FILE))
->setParam('bucket', $bucket->getArrayCopy())
;
$response->noContent();
@ -1651,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 = [];

View file

@ -8,6 +8,7 @@ use Appwrite\Template\Template;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Response;
use Utopia\App;
use Appwrite\Extend\Exception;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@ -17,7 +18,6 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Exception;
use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\ArrayList;
@ -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::GENERAL_CURSOR_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', [
@ -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::GENERAL_SERVER_ERROR);
}
}
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::GENERAL_SERVER_ERROR);
}
$deletes
@ -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::GENERAL_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,14 +341,14 @@ 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);
}
}
$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_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);
throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITE_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::GENERAL_CURSOR_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());
@ -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
@ -621,25 +621,25 @@ 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) {
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));
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')) {
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')) {
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
@ -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,21 +753,21 @@ 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);
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::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::GENERAL_SERVER_ERROR);
}
$memberships = $user->getAttribute('memberships', []);

View file

@ -9,7 +9,7 @@ use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\Config\Config;
use Utopia\Exception;
use Appwrite\Extend\Exception;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Validator\UID;
@ -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.", 400, Exception::GENERAL_CURSOR_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);
@ -378,7 +378,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));
@ -414,7 +414,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));
@ -450,7 +450,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));
@ -489,7 +489,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
@ -532,7 +532,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
@ -545,7 +545,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
@ -582,7 +582,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));
@ -619,7 +619,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', []);
@ -674,7 +674,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', []);
@ -723,7 +723,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);
}
/**

View file

@ -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;
@ -106,11 +106,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();
@ -203,7 +203,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::GENERAL_UNKNOWN_ORIGIN);
}
/*
@ -272,24 +272,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::GENERAL_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::GENERAL_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']);
@ -376,6 +376,26 @@ 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);
}
$template = ($route) ? $route->getLabel('error', null) : null;
if (php_sapi_name() === 'cli') {
@ -421,10 +441,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
@ -537,7 +559,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) {
@ -555,7 +577,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);

View file

@ -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);

View file

@ -3,12 +3,12 @@
use Appwrite\Auth\Auth;
use Appwrite\Messaging\Adapter\Realtime;
use Utopia\App;
use Appwrite\Extend\Exception;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Database\Document;
use Utopia\Storage\Device\DOSpaces;
use Utopia\Database\Validator\Authorization;
use Utopia\Exception;
use Utopia\Storage\Device\Local;
use Utopia\Storage\Device\S3;
use Utopia\Storage\Storage;
@ -31,7 +31,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);
}
/*
@ -80,7 +80,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::GENERAL_RATE_LIMIT_EXCEEDED);
}
}
@ -149,36 +149,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', 501, Exception::USER_AUTH_METHOD_UNSUPPORTED);
break;
}
@ -217,12 +217,14 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
if ($project->getId() !== 'console') {
$payload = new Document($response->getPayload());
$collection = new Document($events->getParam('collection') ?? []);
$bucket = new Document($events->getParam('bucket') ?? []);
$target = Realtime::fromPayload(
event: $events->getParam('event'),
payload: $payload,
project: $project,
collection: $collection
collection: $collection,
bucket: $bucket,
);
Realtime::send(

View file

@ -1,5 +1,6 @@
<?php
use Appwrite\Extend\Exception;
use Appwrite\Utopia\View;
use Utopia\App;
use Utopia\Config\Config;
@ -449,9 +450,9 @@ App::get('/console/version')
if ($version && isset($version['version'])) {
return $response->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);
}
});

View file

@ -1,14 +1,8 @@
<?php
use Appwrite\Specification\Format\OpenAPI3;
use Appwrite\Specification\Format\Swagger2;
use Appwrite\Specification\Specification;
use Appwrite\Utopia\View;
use Utopia\App;
use Utopia\Config\Config;
use Utopia\Exception;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
App::init(function ($layout) {
/** @var Appwrite\Utopia\View $layout */

View file

@ -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\Event\Event;
use Appwrite\Network\Validator\Email;
@ -67,6 +68,7 @@ const APP_LIMIT_USERS = 10000;
const APP_LIMIT_ANTIVIRUS = 20000000; //20MB
const APP_LIMIT_ENCRYPTION = 20000000; //20MB
const APP_LIMIT_COMPRESSION = 20000000; //20MB
const APP_LIMIT_PREVIEW = 10000000; //10MB file size limit for preview endpoint
const APP_CACHE_BUSTER = 201;
const APP_VERSION_STABLE = '0.13.0';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
@ -137,6 +139,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('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');
@ -361,7 +364,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);
@ -706,7 +709,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'] ?? '';

View file

@ -1 +1 @@
Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image.
Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.

View file

@ -0,0 +1,189 @@
<?php
namespace Appwrite\Extend;
class Exception extends \Exception
{
/**
* Error Codes
*
* Naming the error types based on the following convention
* <ENTITY>_<ERROR_TYPE>
*
* Appwrite has the follwing entities:
* - General
* - Users
* - Teams
* - Memberships
* - Avatars
* - Storage
* - Functions
* - Deployments
* - Executions
* - Collections
* - Documents
* - Attributes
* - Indexes
* - Projects
* - Webhooks
* - Keys
* - Platform
* - Domain
*/
/** 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';
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_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';
/** 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';
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_AUTH_METHOD_UNSUPPORTED = 'user_auth_method_unsupported';
/** 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';
/** 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';
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_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';
/** Deployments */
const DEPLOYMENT_NOT_FOUND = 'deployment_not_found';
/** 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';
/** 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';
/** 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';
/** 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_VERIFICATION_FAILED = 'domain_verification_failed';
private $type = '';
public function __construct(string $message, int $code = 0, string $type = Exception::GENERAL_UNKNOWN, \Throwable $previous = null)
{
$this->type = $type;
parent::__construct($message, $code, $previous);
}
/**
* 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;
}
}

View file

@ -240,7 +240,7 @@ class Realtime extends Adapter
* @param Document|null $project
* @return array
*/
public static function fromPayload(string $event, Document $payload, Document $project = null, Document $collection = null): array
public static function fromPayload(string $event, Document $payload, Document $project = null, Document $collection = null, Document $bucket = null): array
{
$channels = [];
$roles = [];
@ -285,7 +285,7 @@ class Realtime extends Adapter
break;
case strpos($event, 'database.documents.') === 0:
if ($collection->isEmpty()) {
throw new \Exception('Collection need to be passed to to Realtime for Document events in the Database.');
throw new \Exception('Collection needs to be passed to Realtime for Document events in the Database.');
}
$channels[] = 'documents';
@ -294,17 +294,14 @@ class Realtime extends Adapter
$roles = ($collection->getAttribute('permission') === 'collection') ? $collection->getRead() : $payload->getRead();
break;
case strpos($event, 'storage.buckets.') === 0:
$channels[] = 'buckets';
$channels[] = 'buckets.' . $payload->getId();
$roles = $payload->getRead();
break;
case strpos($event, 'storage.files') === 0:
if($bucket->isEmpty()) {
throw new \Exception('Bucket needs to be pased to Realtime for File events in the Storage.');
}
$channels[] = 'files';
$channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files';
$channels[] = 'files.' . $payload->getId();
$channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files.' . $payload->getId();
$roles = $payload->getRead();
break;

View file

@ -7,7 +7,7 @@ use Utopia\Database\Document;
use Utopia\Database\Database;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Exception;
use Exception;
abstract class Migration
{

View file

@ -276,6 +276,9 @@ class OpenAPI3 extends Format
break;
case 'Utopia\Database\Validator\UID':
case 'Appwrite\Utopia\Database\Validator\CustomId':
if($route->getLabel('sdk.methodType', '') === 'upload') {
$node['schema']['x-upload-id'] = true;
}
$node['schema']['type'] = $validator->getType();
$node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;

View file

@ -264,6 +264,9 @@ class Swagger2 extends Format
break;
case 'Utopia\Database\Validator\UID':
case 'Appwrite\Utopia\Database\Validator\CustomId':
if($route->getLabel('sdk.methodType', '') === 'upload') {
$node['x-upload-id'] = true;
}
$node['type'] = $validator->getType();
$node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;

View file

@ -22,6 +22,12 @@ class Error extends Model
'default' => '',
'example' => '404',
])
->addRule('type', [
'type' => self::TYPE_STRING,
'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', [
'type' => self::TYPE_STRING,
'description' => 'Server version number.',

View file

@ -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']);
}

View file

@ -851,7 +851,7 @@ class RealtimeCustomClientTest extends Scope
$session = $user['session'] ?? '';
$projectId = $this->getProject()['$id'];
$client = $this->getWebsocket(['files', 'buckets'], [
$client = $this->getWebsocket(['files'], [
'origin' => 'http://localhost',
'cookie' => 'a_session_'.$projectId.'=' . $session
]);
@ -861,9 +861,8 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('data', $response);
$this->assertEquals('connected', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertCount(2, $response['data']['channels']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
$this->assertContains('buckets', $response['data']['channels']);
$this->assertNotEmpty($response['data']['user']);
$this->assertEquals($user['$id'], $response['data']['user']['$id']);
@ -881,18 +880,7 @@ class RealtimeCustomClientTest extends Scope
'write' => ['role:all'],
'permission' => 'bucket'
]);
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
$this->assertArrayHasKey('data', $response);
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(2, $response['data']['channels']);
$this->assertContains('buckets', $response['data']['channels']);
$this->assertContains('buckets.' . $bucket1['body']['$id'], $response['data']['channels']);
$this->assertEquals('storage.buckets.create', $response['data']['event']);
$this->assertNotEmpty($response['data']['payload']);
$data = ['bucketId' => $bucket1['body']['$id']];
/**
* Test File Create
@ -905,7 +893,6 @@ class RealtimeCustomClientTest extends Scope
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
'read' => ['role:all'],
'write' => ['role:all'],
'folderId' => 'xyz',
]);
$response = json_decode($client->receive(), true);
@ -917,7 +904,7 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
$this->assertContains('files.' . $file['body']['$id'], $response['data']['channels']);
$this->assertContains('buckets.' . $data['bucketId'] . '.files.' . $file['body']['$id'], $response['data']['channels']);
$this->assertContains('buckets.' . $data['bucketId'] . '.files', $response['data']['channels']);
$this->assertEquals('storage.files.create', $response['data']['event']);
$this->assertNotEmpty($response['data']['payload']);
@ -944,7 +931,7 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
$this->assertContains('files.' . $file['body']['$id'], $response['data']['channels']);
$this->assertContains('buckets.' . $data['bucketId'] . '.files.' . $file['body']['$id'], $response['data']['channels']);
$this->assertContains('buckets.' . $data['bucketId'] . '.files', $response['data']['channels']);
$this->assertEquals('storage.files.update', $response['data']['event']);
$this->assertNotEmpty($response['data']['payload']);
@ -966,7 +953,7 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
$this->assertContains('files.' . $file['body']['$id'], $response['data']['channels']);
$this->assertContains('buckets.' . $data['bucketId'] . '.files.' . $file['body']['$id'], $response['data']['channels']);
$this->assertContains('buckets.' . $data['bucketId'] . '.files', $response['data']['channels']);
$this->assertEquals('storage.files.delete', $response['data']['event']);
$this->assertNotEmpty($response['data']['payload']);