diff --git a/app/config/errors.php b/app/config/errors.php index 6d7c9544d..105fa9881 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -291,6 +291,28 @@ return [ 'description' => 'Function with the requested ID could not be found.', 'code' => 404, ], + Exception::FUNCTION_RUNTIME_UNSUPPORTED => [ + 'name' => Exception::FUNCTION_RUNTIME_UNSUPPORTED, + 'description' => 'The requested runtime is either inactive or unsupported. Please check the value of the _APP_FUNCTIONS_RUNTIMES environment variable.', + 'code' => 404, + ], + + /** Builds */ + Exception::BUILD_NOT_FOUND => [ + 'name' => Exception::BUILD_NOT_FOUND, + 'description' => 'Build with the requested ID could not be found.', + 'code' => 404, + ], + Exception::BUILD_NOT_READY => [ + 'name' => Exception::BUILD_NOT_READY, + 'description' => 'Build with the requested ID is builing and not ready for execution.', + 'code' => 400, + ], + Exception::BUILD_IN_PROGRESS => [ + 'name' => Exception::BUILD_IN_PROGRESS, + 'description' => 'Build with the requested ID is already in progress. Please wait before you can ret', + 'code' => 400, + ], /** Deployments */ Exception::DEPLOYMENT_NOT_FOUND => [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 69602dc42..43bc48ea9 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1716,7 +1716,7 @@ App::patch('/v1/account/sessions/:sessionId') $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, '', [], []); @@ -1753,7 +1753,7 @@ App::patch('/v1/account/sessions/:sessionId') } } - throw new Exception('Session not found', 404); + throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND); }); App::delete('/v1/account/sessions') diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 6d7b9cf09..6239b3554 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -25,6 +25,7 @@ use Utopia\Validator\WhiteList; use Utopia\Config\Config; use Cron\CronExpression; use Executor\Executor; +use PhpParser\Node\Expr; use Utopia\CLI\Console; use Utopia\Validator\Boolean; @@ -106,7 +107,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); } } @@ -171,7 +172,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); @@ -200,7 +201,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 = []; @@ -311,7 +312,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', ''); @@ -371,7 +372,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } if ($deployment->isEmpty()) { @@ -379,7 +380,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId') } if ($build->isEmpty()) { - throw new Exception('Build not found', 404); + throw new Exception('Build not found', 404, Exception::BUILD_NOT_FOUND); } if ($build->getAttribute('status') !== 'ready') { @@ -430,11 +431,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 @@ -484,7 +485,7 @@ App::post('/v1/functions/:functionId/deployments') $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'); @@ -493,7 +494,7 @@ App::post('/v1/functions/:functionId/deployments') $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 @@ -502,7 +503,7 @@ App::post('/v1/functions/:functionId/deployments') $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'); @@ -516,7 +517,7 @@ App::post('/v1/functions/:functionId/deployments') $fileSize = $request->getContentRangeSize(); $deploymentId = $request->getHeader('x-appwrite-id', $deploymentId); 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) { @@ -530,11 +531,11 @@ App::post('/v1/functions/:functionId/deployments') } 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 @@ -555,7 +556,7 @@ App::post('/v1/functions/:functionId/deployments') $chunksUploaded = $deviceFunctions->upload($fileTmpName, $path, $chunk, $chunks, $metadata); if (empty($chunksUploaded)) { - throw new Exception('Failed moving file', 500); + throw new Exception('Failed moving file', 500, Exception::GENERAL_SERVER_ERROR); } if($chunksUploaded === $chunks) { @@ -664,7 +665,7 @@ App::get('/v1/functions/:functionId/deployments') $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)) { @@ -723,7 +724,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId') $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); } $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -766,7 +767,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId') $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); } $deployment = $dbForProject->getDocument('deployments', $deploymentId); @@ -832,7 +833,7 @@ 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); } $runtimes = Config::getParam('runtimes', []); @@ -840,7 +841,7 @@ App::post('/v1/functions/:functionId/executions') $runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null; if (\is_null($runtime)) { - throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported', 400); + throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported', 400, Exception::FUNCTION_RUNTIME_UNSUPPORTED); } $deployment = Authorization::skip(fn() => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', ''))); @@ -856,17 +857,17 @@ App::post('/v1/functions/:functionId/executions') /** Check if build has completed */ $build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''))); if ($build->isEmpty()) { - throw new Exception('Build not found', 404); + throw new Exception('Build not found', 404, Exception::BUILD_NOT_FOUND); } if ($build->getAttribute('status') !== 'ready') { - throw new Exception('Build not ready', 400); + throw new Exception('Build not ready', 400, Exception::BUILD_NOT_READY); } $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(); @@ -1000,14 +1001,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); } } @@ -1050,17 +1051,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); @@ -1092,21 +1093,21 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId') $deployment = $dbForProject->getDocument('deployments', $deploymentId); if ($function->isEmpty()) { - throw new Exception('Function not found', 404); + throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND); } if ($deployment->isEmpty()) { - throw new Exception('Deployment not found', 404); + throw new Exception('Deployment not found', 404, Exception::DEPLOYMENT_NOT_FOUND); } $build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $buildId)); if ($build->isEmpty()) { - throw new Exception('Build not found', 404); + throw new Exception('Build not found', 404, Exception::BUILD_NOT_FOUND); } if ($build->getAttribute('status') !== 'failed') { - throw new Exception('Build not failed', 400); + throw new Exception('Build not failed', 400, Exception::BUILD_IN_PROGRESS); } // Enqueue a message to start the build diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index c39606fdd..4f396990f 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -98,10 +98,16 @@ class Exception extends \Exception /** Functions */ const FUNCTION_NOT_FOUND = 'function_not_found'; + const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; /** Deployments */ const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; + /** Builds */ + const BUILD_NOT_FOUND = 'build_not_found'; + const BUILD_NOT_READY = 'build_not_ready'; + const BUILD_IN_PROGRESS = 'build_in_progress'; + /** Execution */ const EXECUTION_NOT_FOUND = 'execution_not_found';