diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 7542b24d35..e58e1f211f 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -19,16 +19,13 @@ use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; use Utopia\Database\Database; -use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Authorization as AuthorizationException; use Utopia\Database\Exception\Conflict as ConflictException; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; -use Utopia\Database\Exception\Query as QueryException; use Utopia\Database\Exception\Restricted as RestrictedException; use Utopia\Database\Exception\Structure as StructureException; -use Utopia\Database\Exception\Timeout as TimeoutException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; @@ -657,16 +654,10 @@ App::put('/v1/databases/:databaseId') throw new Exception(Exception::DATABASE_NOT_FOUND); } - try { - $database = $dbForProject->updateDocument('databases', $databaseId, $database - ->setAttribute('name', $name) - ->setAttribute('enabled', $enabled) - ->setAttribute('search', implode(' ', [$databaseId, $name]))); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage()); - } + $database = $dbForProject->updateDocument('databases', $databaseId, $database + ->setAttribute('name', $name) + ->setAttribute('enabled', $enabled) + ->setAttribute('search', implode(' ', [$databaseId, $name]))); $queueForEvents->setParam('databaseId', $database->getId()); @@ -1015,19 +1006,14 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') $enabled ??= $collection->getAttribute('enabled', true); - try { - $collection = $dbForProject->updateDocument('database_' . $database->getInternalId(), $collectionId, $collection - ->setAttribute('name', $name) - ->setAttribute('$permissions', $permissions) - ->setAttribute('documentSecurity', $documentSecurity) - ->setAttribute('enabled', $enabled) - ->setAttribute('search', implode(' ', [$collectionId, $name]))); - $dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage()); - } + $collection = $dbForProject->updateDocument('database_' . $database->getInternalId(), $collectionId, $collection + ->setAttribute('name', $name) + ->setAttribute('$permissions', $permissions) + ->setAttribute('documentSecurity', $documentSecurity) + ->setAttribute('enabled', $enabled) + ->setAttribute('search', implode(' ', [$collectionId, $name]))); + + $dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity); $queueForEvents ->setContext('database', $database) @@ -2822,13 +2808,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $checkPermissions($collection, $document, Database::PERMISSION_CREATE); - try { $document = $dbForProject->createDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } catch (DuplicateException $exception) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); - } // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { @@ -2936,14 +2916,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $filters = Query::groupByType($queries)['filters']; - try { - $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); - $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filters, APP_LIMIT_COUNT); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (QueryException $e) { - throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $e->getMessage()); - } + $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); + $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filters, APP_LIMIT_COUNT); // Add $collectionId and $databaseId for all documents $processDocument = (function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool { @@ -3069,13 +3043,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $queries = Query::parseQueries($queries); - try { - $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (QueryException $e) { - throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $e->getMessage()); - } + $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3387,22 +3355,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $setCollection($collection, $newDocument); - try { - $document = $dbForProject->withRequestTimestamp( - $requestTimestamp, - fn() => $dbForProject->updateDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), - $document->getId(), - $newDocument - ) - ); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (DuplicateException) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } + $document = $dbForProject->withRequestTimestamp( + $requestTimestamp, + fn() => $dbForProject->updateDocument( + 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + $document->getId(), + $newDocument + ) + ); // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { @@ -3502,16 +3462,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu } $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) { - try { - $dbForProject->deleteDocument( - 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), - $documentId - ); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (RestrictedException) { - throw new Exception(Exception::DOCUMENT_DELETE_RESTRICTED); - } + $dbForProject->deleteDocument( + 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), + $documentId + ); }); // Add $collectionId and $databaseId for all documents diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index efe2515468..26ae0adacf 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -581,111 +581,95 @@ App::post('/v1/storage/buckets/:bucketId/files') $openSSLIV = \bin2hex($iv); } - try { - if ($file->isEmpty()) { - $doc = new Document([ - '$id' => $fileId, - '$permissions' => $permissions, - 'bucketId' => $bucket->getId(), - 'bucketInternalId' => $bucket->getInternalId(), - 'name' => $fileName, - 'path' => $path, - 'signature' => $fileHash, - 'mimeType' => $mimeType, - 'sizeOriginal' => $fileSize, - 'sizeActual' => $sizeActual, - 'algorithm' => $algorithm, - 'comment' => '', - 'chunksTotal' => $chunks, - 'chunksUploaded' => $chunksUploaded, - 'openSSLVersion' => $openSSLVersion, - 'openSSLCipher' => $openSSLCipher, - 'openSSLTag' => $openSSLTag, - 'openSSLIV' => $openSSLIV, - 'search' => implode(' ', [$fileId, $fileName]), - 'metadata' => $metadata, - ]); + if ($file->isEmpty()) { + $doc = new Document([ + '$id' => $fileId, + '$permissions' => $permissions, + 'bucketId' => $bucket->getId(), + 'bucketInternalId' => $bucket->getInternalId(), + 'name' => $fileName, + 'path' => $path, + 'signature' => $fileHash, + 'mimeType' => $mimeType, + 'sizeOriginal' => $fileSize, + 'sizeActual' => $sizeActual, + 'algorithm' => $algorithm, + 'comment' => '', + 'chunksTotal' => $chunks, + 'chunksUploaded' => $chunksUploaded, + 'openSSLVersion' => $openSSLVersion, + 'openSSLCipher' => $openSSLCipher, + 'openSSLTag' => $openSSLTag, + 'openSSLIV' => $openSSLIV, + 'search' => implode(' ', [$fileId, $fileName]), + 'metadata' => $metadata, + ]); - $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); - } else { - $file = $file - ->setAttribute('$permissions', $permissions) - ->setAttribute('signature', $fileHash) - ->setAttribute('mimeType', $mimeType) - ->setAttribute('sizeActual', $sizeActual) - ->setAttribute('algorithm', $algorithm) - ->setAttribute('openSSLVersion', $openSSLVersion) - ->setAttribute('openSSLCipher', $openSSLCipher) - ->setAttribute('openSSLTag', $openSSLTag) - ->setAttribute('openSSLIV', $openSSLIV) - ->setAttribute('metadata', $metadata) - ->setAttribute('chunksUploaded', $chunksUploaded); + $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); + } else { + $file = $file + ->setAttribute('$permissions', $permissions) + ->setAttribute('signature', $fileHash) + ->setAttribute('mimeType', $mimeType) + ->setAttribute('sizeActual', $sizeActual) + ->setAttribute('algorithm', $algorithm) + ->setAttribute('openSSLVersion', $openSSLVersion) + ->setAttribute('openSSLCipher', $openSSLCipher) + ->setAttribute('openSSLTag', $openSSLTag) + ->setAttribute('openSSLIV', $openSSLIV) + ->setAttribute('metadata', $metadata) + ->setAttribute('chunksUploaded', $chunksUploaded); - /** - * Validate create permission and skip authorization in updateDocument - * Without this, the file creation will fail when user doesn't have update permission - * However as with chunk upload even if we are updating, we are essentially creating a file - * adding it's new chunk so we validate create permission instead of update - */ - $validator = new Authorization(Database::PERMISSION_CREATE); - if (!$validator->isValid($bucket->getCreate())) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); + /** + * Validate create permission and skip authorization in updateDocument + * Without this, the file creation will fail when user doesn't have update permission + * However as with chunk upload even if we are updating, we are essentially creating a file + * adding it's new chunk so we validate create permission instead of update + */ + $validator = new Authorization(Database::PERMISSION_CREATE); + if (!$validator->isValid($bucket->getCreate())) { + throw new Exception(Exception::USER_UNAUTHORIZED); } - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } catch (DuplicateException) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); + $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } } else { - try { - if ($file->isEmpty()) { - $doc = new Document([ - '$id' => ID::custom($fileId), - '$permissions' => $permissions, - 'bucketId' => $bucket->getId(), - 'bucketInternalId' => $bucket->getInternalId(), - 'name' => $fileName, - 'path' => $path, - 'signature' => '', - 'mimeType' => '', - 'sizeOriginal' => $fileSize, - 'sizeActual' => 0, - 'algorithm' => '', - 'comment' => '', - 'chunksTotal' => $chunks, - 'chunksUploaded' => $chunksUploaded, - 'search' => implode(' ', [$fileId, $fileName]), - 'metadata' => $metadata, - ]); + if ($file->isEmpty()) { + $doc = new Document([ + '$id' => ID::custom($fileId), + '$permissions' => $permissions, + 'bucketId' => $bucket->getId(), + 'bucketInternalId' => $bucket->getInternalId(), + 'name' => $fileName, + 'path' => $path, + 'signature' => '', + 'mimeType' => '', + 'sizeOriginal' => $fileSize, + 'sizeActual' => 0, + 'algorithm' => '', + 'comment' => '', + 'chunksTotal' => $chunks, + 'chunksUploaded' => $chunksUploaded, + 'search' => implode(' ', [$fileId, $fileName]), + 'metadata' => $metadata, + ]); - $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); - } else { - $file = $file - ->setAttribute('chunksUploaded', $chunksUploaded) - ->setAttribute('metadata', $metadata); + $file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc); + } else { + $file = $file + ->setAttribute('chunksUploaded', $chunksUploaded) + ->setAttribute('metadata', $metadata); - /** - * Validate create permission and skip authorization in updateDocument - * Without this, the file creation will fail when user doesn't have update permission - * However as with chunk upload even if we are updating, we are essentially creating a file - * adding it's new chunk so we validate create permission instead of update - */ - $validator = new Authorization(Database::PERMISSION_CREATE); - if (!$validator->isValid($bucket->getCreate())) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } - $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); + /** + * Validate create permission and skip authorization in updateDocument + * Without this, the file creation will fail when user doesn't have update permission + * However as with chunk upload even if we are updating, we are essentially creating a file + * adding it's new chunk so we validate create permission instead of update + */ + $validator = new Authorization(Database::PERMISSION_CREATE); + if (!$validator->isValid($bucket->getCreate())) { + throw new Exception(Exception::USER_UNAUTHORIZED); } - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (StructureException $exception) { - throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $exception->getMessage()); - } catch (DuplicateException) { - throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS); + $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } } @@ -1383,11 +1367,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId') } if ($fileSecurity && !$valid) { - try { - $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } + $file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file); } else { $file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file)); } @@ -1471,11 +1451,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId') ; if ($fileSecurity && !$valid) { - try { - $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId); - } catch (AuthorizationException) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } + $deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId); } else { $deleted = Authorization::skip(fn() => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId)); } diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 2801e45bb5..308f19e45e 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1036,14 +1036,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::TEAM_NOT_FOUND); } - try { - $dbForProject->deleteDocument('memberships', $membership->getId()); - } catch (AuthorizationException $exception) { - throw new Exception(Exception::USER_UNAUTHORIZED); - } catch (\Exception $exception) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove membership from DB'); - } - + $dbForProject->deleteDocument('memberships', $membership->getId()); $dbForProject->deleteCachedDocument('users', $user->getId()); if ($membership->getAttribute('confirm')) { // Count only confirmed members diff --git a/app/controllers/general.php b/app/controllers/general.php index 86ad0a8d8e..85f80aa2a4 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -810,7 +810,7 @@ App::error() } } - if ($logger && ($publish || $error->getCode() === 0)) { + if ($logger && $publish) { try { /** @var Utopia\Database\Document $user */ $user = $utopia->getResource('user'); @@ -853,6 +853,7 @@ App::error() Console::info('Log pushed with status code: ' . $responseCode); } + $class = \get_class($error); $code = $error->getCode(); $message = $error->getMessage(); $file = $error->getFile(); @@ -873,27 +874,44 @@ App::error() Console::error('[Error] Line: ' . $line); } - /** Handle Utopia Errors */ - if ($error instanceof Utopia\Exception) { - $error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error); - switch ($code) { - case 400: - $error->setType(AppwriteException::GENERAL_ARGUMENT_INVALID); - break; - case 404: - $error->setType(AppwriteException::GENERAL_ROUTE_NOT_FOUND); - break; - } - } elseif ($error instanceof Utopia\Database\Exception\Conflict) { - $error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, previous: $error); - $code = $error->getCode(); - $message = $error->getMessage(); - } elseif ($error instanceof Utopia\Database\Exception\Timeout) { - $error = new AppwriteException(AppwriteException::DATABASE_TIMEOUT, previous: $error); - $code = $error->getCode(); - $message = $error->getMessage(); + switch ($class) { + case 'Utopia\Exception': + $error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error); + switch ($code) { + case 400: + $error->setType(AppwriteException::GENERAL_ARGUMENT_INVALID); + break; + case 404: + $error->setType(AppwriteException::GENERAL_ROUTE_NOT_FOUND); + break; + } + break; + case 'Utopia\Database\Exception\Conflict': + $error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, previous: $error); + break; + case 'Utopia\Database\Exception\Timeout': + $error = new AppwriteException(AppwriteException::DATABASE_TIMEOUT, previous: $error); + break; + case 'Utopia\Database\Exception\Query': + $error = new AppwriteException(AppwriteException::GENERAL_QUERY_INVALID, $error->getMessage(), previous: $error); + break; + case 'Utopia\Database\Exception\Structure': + $error = new AppwriteException(AppwriteException::DOCUMENT_INVALID_STRUCTURE, $error->getMessage(), previous: $error); + break; + case 'Utopia\Database\Exception\Duplicate': + $error = new AppwriteException(AppwriteException::DOCUMENT_ALREADY_EXISTS); + break; + case 'Utopia\Database\Exception\Restricted': + $error = new AppwriteException(AppwriteException::DOCUMENT_DELETE_RESTRICTED); + break; + case 'Utopia\Database\Exception\Authorization': + $error = new AppwriteException(AppwriteException::USER_UNAUTHORIZED); + break; } + $code = $error->getCode(); + $message = $error->getMessage(); + /** Wrap all exceptions inside Appwrite\Extend\Exception */ if (!($error instanceof AppwriteException)) { $error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error);