diff --git a/crates/service/web/storyteller_web/src/docs/api_doc.rs b/crates/service/web/storyteller_web/src/docs/api_doc.rs index faf04fb173..58fcdae997 100644 --- a/crates/service/web/storyteller_web/src/docs/api_doc.rs +++ b/crates/service/web/storyteller_web/src/docs/api_doc.rs @@ -651,7 +651,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux BatchGetUserBookmarksError, BatchGetUserBookmarksQueryParams, BatchGetUserBookmarksResponse, - BatchGetUserRatingError, BatchGetUserRatingQueryParams, BatchGetUserRatingResponse, GenerateGptImage1TextToImageImageQuality, @@ -668,17 +667,13 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux GetPromptImageContextItem, BookmarkRow, ByQueueStats, - ChangeMediaFileAnimationTypeError, ChangeMediaFileAnimationTypeRequest, - ChangeMediaFileEngineCategoryError, ChangeMediaFileEngineCategoryRequest, - ChangeMediaFileVisibilityError, ChangeMediaFileVisibilityRequest, CreateAccountErrorResponse, CreateAccountErrorType, CreateAccountRequest, CreateAccountSuccessResponse, - CreateBetaKeysError, CreateBetaKeysRequest, CreateBetaKeysSuccessResponse, CreateCheckoutSessionError, @@ -687,7 +682,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux CreateCommentError, CreateCommentRequest, CreateCommentSuccessResponse, - CreateFeaturedItemError, CreateFeaturedItemRequest, CreateFeaturedItemSuccessResponse, CreateSceneSuccessResponse, @@ -697,27 +691,22 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux DeleteCommentError, DeleteCommentPathInfo, DeleteCommentRequest, - DeleteFeaturedItemError, DeleteFeaturedItemRequest, DeleteMediaFilePathInfo, DeleteMediaFileRequest, DeleteUserBookmarkError, DeleteUserBookmarkPathInfo, DeleteUserBookmarkRequest, - DeleteWeightError, DeleteWeightPathInfo, DeleteWeightRequest, DismissFinishedSessionJobsSuccessResponse, - EditBetaKeyDistributedFlagError, EditBetaKeyDistributedFlagPathInfo, EditBetaKeyDistributedFlagRequest, EditBetaKeyDistributedFlagSuccessResponse, - EditBetaKeyNoteError, EditBetaKeyNotePathInfo, EditBetaKeyNoteRequest, EditBetaKeyNoteSuccessResponse, EditUserFeatureFlagPathInfo, - EditUserFeatureFlagsError, EditUserFeatureFlagsOption, EditUserFeatureFlagsRequest, ModerationSendAlertRequest, @@ -790,13 +779,10 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux GptImage1EditImageNumImages, GptImage1EditImageImageQuality, GptImage1EditImageResponse, - ChangePasswordError, ChangePasswordRequest, ChangePasswordResponse, - EditEmailError, EditEmailRequest, EditEmailResponse, - EditUsernameError, EditUsernameRequest, EditUsernameResponse, EnqueueFaceFusionCropDimensions, @@ -870,7 +856,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux GenerateVeo2ImageToVideoResponse, GetInferenceJobStatusPathInfo, GetInferenceJobStatusSuccessResponse, - GetIsFeaturedItemError, GetIsFeaturedItemPathInfo, GetIsFeaturedItemSuccessResponse, GetMediaFileModelInfo, @@ -882,9 +867,7 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux GetPromptSuccessResponse, GetUnifiedQueueStatsError, GetUnifiedQueueStatsSuccessResponse, - GetUserRatingError, GetUserRatingResponse, - GetWeightError, GetWeightPathInfo, GetWeightResponse, GoogleCreateAccountRequest, @@ -898,7 +881,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux ListActiveUserSubscriptionsResponse, ListAvailableWeightsQuery, ListAvailableWeightsSuccessResponse, - ListBetaKeysError, ListBetaKeysFilterOption, ListBetaKeysQueryParams, ListBetaKeysSuccessResponse, @@ -943,7 +925,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux ListSessionRequestDetailsResponse, ListSessionResultDetailsResponse, ListSessionStatusDetailsResponse, - ListTagsForEntityError, ListTagsForEntityPathInfo, ListTagsForEntitySuccessResponse, ListUserBookmarksForEntityError, @@ -953,7 +934,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux ListUserBookmarksForUserSuccessResponse, ListUserBookmarksPathInfo, ListWeightError, - ListWeightsByUserError, ListWeightsByUserPathInfo, ListWeightsByUserSuccessResponse, LogBrowserSessionError, @@ -963,7 +943,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux LoginErrorType, LoginRequest, LoginSuccessResponse, - LogoutError, LogoutSuccessResponse, MediaFileData, MediaFileForUserListItem, @@ -980,24 +959,20 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux ModernInferenceQueueStats, PinnedMediaFile, PinnedModelWeightForList, - ProfileError, PromptInfo, RatingRow, RedeemBetaKeyRequest, RedeemBetaKeySuccessResponse, RemoveImageBackgroundRequest, RemoveImageBackgroundResponse, - RenameMediaFileError, RenameMediaFileRequest, RequestDetailsResponse, ResultDetailsResponse, StaffAuditLogResponse, SearchFeaturedMediaFileListItem, - SearchFeaturedMediaFilesError, SearchFeaturedMediaFilesQueryParams, SearchFeaturedMediaFilesSuccessResponse, SearchMediaFileListItem, - SearchMediaFilesError, SearchMediaFilesQueryParams, SearchMediaFilesSuccessResponse, SearchModelWeightsError, @@ -1005,31 +980,23 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux SearchModelWeightsSortDirection, SearchModelWeightsSortField, SearchModelWeightsSuccessResponse, - SessionTokenInfoError, SessionTokenInfoSuccessResponse, - SetMediaFileCoverImageError, SetMediaFileCoverImageRequest, - SetModelWeightCoverImageError, SetModelWeightCoverImagePathInfo, SetModelWeightCoverImageRequest, SetModelWeightCoverImageResponse, - SetTagsForEntityError, SetTagsForEntityPathInfo, SetTagsForEntityRequest, SetTagsForEntitySuccessResponse, - SetUserRatingError, SetUserRatingRequest, SetUserRatingResponse, StatusAlertCategory, - StatusAlertError, StatusAlertInfo, StatusAlertResponse, StatusDetailsResponse, SubscriptionProductKey, - TerminateInferenceJobError, TerminateInferenceJobPathInfo, TerminateInferenceJobSuccessResponse, - UpdateWeightError, UpdateWeightPathInfo, UpdateWeightRequest, UploadAudioMediaFileForm, diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/create_api_token.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/create_api_token.rs index ffacc0923e..766d2a6a1d 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/create_api_token.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/create_api_token.rs @@ -11,6 +11,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::api_tokens::create_api_token::create_api_token_for_user; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -28,41 +29,13 @@ pub struct CreateApiTokenResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum CreateApiTokenError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CreateApiTokenError { - fn status_code(&self) -> StatusCode { - match *self { - CreateApiTokenError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateApiTokenError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateApiTokenError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for CreateApiTokenError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn create_api_token_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -70,20 +43,20 @@ pub async fn create_api_token_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - CreateApiTokenError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(CreateApiTokenError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; if user_session.is_banned { warn!("banned users cannot create API tokens"); - return Err(CreateApiTokenError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let creator_ip_address = get_request_ip(&http_request); @@ -96,7 +69,7 @@ pub async fn create_api_token_handler( .await .map_err(|e| { warn!("API token creation errror: {:?}", e); - CreateApiTokenError::ServerError + CommonWebError::from_anyhow_error(e) })?; let response = CreateApiTokenResponse { @@ -105,7 +78,7 @@ pub async fn create_api_token_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| CreateApiTokenError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/delete_api_token.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/delete_api_token.rs index 530e71d795..9501ff1205 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/delete_api_token.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/delete_api_token.rs @@ -13,6 +13,7 @@ use mysql_queries::queries::api_tokens::delete_api_token::delete_api_token; use mysql_queries::queries::api_tokens::list_available_api_tokens_for_user::list_available_api_tokens_for_user; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -31,43 +32,13 @@ pub struct DeleteApiTokenResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum DeleteApiTokenError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for DeleteApiTokenError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteApiTokenError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteApiTokenError::NotFound => StatusCode::NOT_FOUND, - DeleteApiTokenError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteApiTokenError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteApiTokenError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn delete_api_token_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -75,20 +46,20 @@ pub async fn delete_api_token_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteApiTokenError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteApiTokenError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; if user_session.is_banned { warn!("banned users cannot edit API tokens"); - return Err(DeleteApiTokenError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let tokens = list_available_api_tokens_for_user( @@ -97,7 +68,7 @@ pub async fn delete_api_token_handler( .await .map_err(|e| { warn!("Error querying tokens: {:?}", e); - DeleteApiTokenError::ServerError + CommonWebError::from_anyhow_error(e) })?; let valid_token = tokens.iter() @@ -106,7 +77,7 @@ pub async fn delete_api_token_handler( if !valid_token { warn!("Invalid API Token"); - return Err(DeleteApiTokenError::NotFound); + return Err(CommonWebError::NotFound); } let creator_ip_address = get_request_ip(&http_request); @@ -119,7 +90,7 @@ pub async fn delete_api_token_handler( .await .map_err(|e| { error!("Error with query: {:?}", e); - DeleteApiTokenError::ServerError + CommonWebError::from_anyhow_error(e) }); let response = DeleteApiTokenResponse { @@ -127,7 +98,7 @@ pub async fn delete_api_token_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| DeleteApiTokenError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/edit_api_token.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/edit_api_token.rs index 4545ad0661..69574bcce5 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/edit_api_token.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/edit_api_token.rs @@ -12,6 +12,7 @@ use mysql_queries::queries::api_tokens::edit_api_token::edit_api_token; use mysql_queries::queries::api_tokens::list_available_api_tokens_for_user::list_available_api_tokens_for_user; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -32,43 +33,13 @@ pub struct EditApiTokenResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum EditApiTokenError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for EditApiTokenError { - fn status_code(&self) -> StatusCode { - match *self { - EditApiTokenError::BadInput(_) => StatusCode::BAD_REQUEST, - EditApiTokenError::NotFound => StatusCode::NOT_FOUND, - EditApiTokenError::NotAuthorized => StatusCode::UNAUTHORIZED, - EditApiTokenError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditApiTokenError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn edit_api_token_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -76,20 +47,20 @@ pub async fn edit_api_token_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - EditApiTokenError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(EditApiTokenError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; if user_session.is_banned { warn!("banned users cannot edit API tokens"); - return Err(EditApiTokenError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let tokens = list_available_api_tokens_for_user( @@ -98,7 +69,7 @@ pub async fn edit_api_token_handler( .await .map_err(|e| { warn!("Error querying tokens: {:?}", e); - EditApiTokenError::ServerError + CommonWebError::from_anyhow_error(e) })?; let valid_token = tokens.iter() @@ -107,7 +78,7 @@ pub async fn edit_api_token_handler( if !valid_token { warn!("Invalid API Token"); - return Err(EditApiTokenError::NotFound); + return Err(CommonWebError::NotFound); } let creator_ip_address = get_request_ip(&http_request); @@ -121,7 +92,7 @@ pub async fn edit_api_token_handler( .await .map_err(|e| { error!("Error with query: {:?}", e); - EditApiTokenError::ServerError + CommonWebError::from_anyhow_error(e) }); let response = EditApiTokenResponse { @@ -129,7 +100,7 @@ pub async fn edit_api_token_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| EditApiTokenError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/list_api_tokens.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/list_api_tokens.rs index 53a20533c6..81e96c8fd4 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/list_api_tokens.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/api_tokens/list_api_tokens.rs @@ -11,6 +11,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::api_tokens::list_available_api_tokens_for_user::list_available_api_tokens_for_user; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Success Response =============== @@ -30,38 +31,12 @@ pub struct ApiToken { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum ListApiTokensError { - NotAuthorized, - ServerError, -} - -impl ResponseError for ListApiTokensError { - fn status_code(&self) -> StatusCode { - match *self { - ListApiTokensError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListApiTokensError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListApiTokensError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn list_api_tokens_handler( http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -69,20 +44,20 @@ pub async fn list_api_tokens_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListApiTokensError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ListApiTokensError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; if user_session.is_banned { warn!("banned users cannot use API tokens"); - return Err(ListApiTokensError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let api_tokens = list_available_api_tokens_for_user( @@ -91,7 +66,7 @@ pub async fn list_api_tokens_handler( .await .map_err(|e| { warn!("API token query error: {:?}", e); - ListApiTokensError::ServerError + CommonWebError::from_anyhow_error(e) })?; let mut api_tokens = api_tokens.into_iter() @@ -111,7 +86,7 @@ pub async fn list_api_tokens_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListApiTokensError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/create_category.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/create_category.rs index dbe87a9b7d..13bac16139 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/create_category.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/create_category.rs @@ -12,6 +12,7 @@ use mysql_queries::queries::model_categories::create_category::{create_category, use tokens::tokens::model_categories::ModelCategoryToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; const DEFAULT_CAN_DIRECTLY_HAVE_MODELS : bool = true; const DEFAULT_CAN_HAVE_SUBCATEGORIES : bool = false; @@ -50,41 +51,13 @@ pub struct CreateCategoryResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum CreateCategoryError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CreateCategoryError { - fn status_code(&self) -> StatusCode { - match *self { - CreateCategoryError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateCategoryError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateCategoryError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for CreateCategoryError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn create_category_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -92,14 +65,14 @@ pub async fn create_category_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - CreateCategoryError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(CreateCategoryError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -109,7 +82,7 @@ pub async fn create_category_handler( let model_type = match request.model_type { None => { - return Err(CreateCategoryError::BadInput("no model type".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("no model type".to_string())); } Some(ModelType::Tts) => "tts", Some(ModelType::W2l) => "w2l", @@ -117,11 +90,11 @@ pub async fn create_category_handler( let idempotency_token = request.idempotency_token .clone() - .ok_or(CreateCategoryError::BadInput("no idempotency token provided".to_string()))?; + .ok_or(CommonWebError::BadInputWithSimpleMessage("no idempotency token provided".to_string()))?; let name = request.name .clone() - .ok_or(CreateCategoryError::BadInput("no name provided".to_string()))?; + .ok_or(CommonWebError::BadInputWithSimpleMessage("no name provided".to_string()))?; let category_token = ModelCategoryToken::generate().to_string(); @@ -164,7 +137,7 @@ pub async fn create_category_handler( Ok(_) => {}, Err(err) => { warn!("Create category edit DB error: {:?}", err); - return Err(CreateCategoryError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -174,7 +147,7 @@ pub async fn create_category_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| CreateCategoryError::ServerError)?; + ?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/get_category.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/get_category.rs index 804415fd1a..a3099bfa44 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/get_category.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/get_category.rs @@ -12,6 +12,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::model_categories::get_category_by_token::get_category_by_token; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -63,39 +64,13 @@ pub struct DisplayCategory { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum GetCategoryError { - NotFound, - ServerError, -} - -impl ResponseError for GetCategoryError { - fn status_code(&self) -> StatusCode { - match *self { - GetCategoryError::NotFound => StatusCode::NOT_FOUND, - GetCategoryError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetCategoryError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn get_category_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -103,7 +78,7 @@ pub async fn get_category_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetCategoryError::ServerError + CommonWebError::from_error(e) })?; // TODO: We don't have any permissions for categories. This is a proxy. @@ -120,11 +95,11 @@ pub async fn get_category_handler( }, Ok(None) => { warn!("could not find category"); - return Err(GetCategoryError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("error looking up category: {:?}", err); - return Err(GetCategoryError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); }, }; @@ -156,7 +131,7 @@ pub async fn get_category_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetCategoryError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_categories.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_categories.rs index a802ca6e6e..889251713f 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_categories.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_categories.rs @@ -3,21 +3,18 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use log::error; use datetimes::CHRONO_DATETIME_UNIX_EPOCH; use enums::by_table::model_categories::model_type::ModelType; -use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use tokens::tokens::model_categories::ModelCategoryToken; use crate::configs::static_model::categories::synthetic_category_list::SYNTHETIC_CATEGORY_LIST; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::cached_queries::list_cached_tts_categories_for_public_dropdown::list_cached_tts_categories_for_public_dropdown_db_pool; use crate::state::server_state::ServerState; @@ -64,45 +61,19 @@ pub struct DisplayCategory { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum ListTtsCategoriesError { - NotAuthorized, - ServerError, -} - -impl ResponseError for ListTtsCategoriesError { - fn status_code(&self) -> StatusCode { - match *self { - ListTtsCategoriesError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListTtsCategoriesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTtsCategoriesError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn list_tts_categories_handler( _http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let database_categories = list_cached_tts_categories_for_public_dropdown_db_pool( &server_state.caches.ephemeral.database_tts_category_list, &server_state.mysql_pool) .await .map_err(|e| { error!("error querying categories from db/cache: {:?}", e); - ListTtsCategoriesError::ServerError + CommonWebError::from_anyhow_error(e) })?; // NB: These will be already sorted. @@ -164,7 +135,7 @@ pub async fn list_tts_categories_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ListTtsCategoriesError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_model_assigned_categories.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_model_assigned_categories.rs index b3cd55143d..3c79f43985 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_model_assigned_categories.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/categories/tts/list_tts_model_assigned_categories.rs @@ -3,20 +3,17 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Path; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use log::warn; -use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use mysql_queries::queries::tts::tts_category_assignments::list_assigned_tts_categories_query_builder::ListAssignedTtsCategoriesQueryBuilder; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -65,43 +62,19 @@ pub struct DisplayCategory { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum ListTtsModelAssignedCategoriesError { - ServerError, -} - -impl ResponseError for ListTtsModelAssignedCategoriesError { - fn status_code(&self) -> StatusCode { - match *self { - ListTtsModelAssignedCategoriesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTtsModelAssignedCategoriesError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn list_tts_model_assigned_categories_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { warn!("Could not acquire DB pool: {:?}", e); - ListTtsModelAssignedCategoriesError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -110,7 +83,7 @@ pub async fn list_tts_model_assigned_categories_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListTtsModelAssignedCategoriesError::ServerError + CommonWebError::from_error(e) })?; // TODO: We don't have any permissions for categories. This is a proxy. @@ -130,7 +103,7 @@ pub async fn list_tts_model_assigned_categories_handler( Ok(results) => results, Err(err) => { warn!("DB error: {:?}", err); - return Err(ListTtsModelAssignedCategoriesError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -162,7 +135,7 @@ pub async fn list_tts_model_assigned_categories_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ListTtsModelAssignedCategoriesError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/engine/get_scene_handler.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/engine/get_scene_handler.rs index dbb3499311..44426fce28 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/engine/get_scene_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/engine/get_scene_handler.rs @@ -15,6 +15,7 @@ use mysql_queries::queries::media_files::get::get_media_file::get_media_file; use tokens::tokens::media_files::MediaFileToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -43,45 +44,14 @@ pub struct MediaFileInfo { pub created_at: DateTime, pub updated_at: DateTime, } - -#[derive(Debug, ToSchema)] -pub enum GetSceneError { - ServerError, - NotFound, -} - -impl ResponseError for GetSceneError { - fn status_code(&self) -> StatusCode { - match *self { - GetSceneError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetSceneError::NotFound => StatusCode::NOT_FOUND, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetSceneError::ServerError => "server error".to_string(), - GetSceneError::NotFound => "not found".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetSceneError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( get, path = "/v1/engine/scene/{token}", responses( (status = 200, description = "Found", body = GetSceneSuccessResponse), - (status = 404, description = "Not found", body = GetSceneError), - (status = 500, description = "Server error", body = GetSceneError), + (status = 404, description = "Not found", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("path" = GetScenePathInfo, description = "Path for Request") @@ -90,7 +60,7 @@ impl fmt::Display for GetSceneError { pub async fn get_scene_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let media_file_token = path.into_inner().token; @@ -98,7 +68,7 @@ pub async fn get_scene_handler( false, &server_state).await?; let body = serde_json::to_string(&response) - .map_err(|e| GetSceneError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") @@ -109,7 +79,7 @@ async fn modern_media_file_lookup( media_file_token: &MediaFileToken, show_deleted_results: bool, server_state: &ServerState, -) -> Result { +) -> Result { let result = get_media_file( media_file_token, @@ -120,9 +90,9 @@ async fn modern_media_file_lookup( let result = match result { Err(e) => { warn!("query error: {:?}", e); - return Err(GetSceneError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } - Ok(None) => return Err(GetSceneError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Ok(Some(result)) => result, }; diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/events/list_events.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/events/list_events.rs index 01a31b7acf..50395a9343 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/events/list_events.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/events/list_events.rs @@ -8,6 +8,7 @@ use derive_more::Display; use log::error; use crate::http_server::common_responses::user_avatars::default_avatar_color_from_username::default_avatar_color_from_username; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::user_avatars::default_avatar_from_username::default_avatar_from_username; use mysql_queries::queries::public_event_feed::list_public_event_feed_items::list_public_event_feed_items; @@ -54,39 +55,17 @@ pub struct ListEventsSuccessResponse { pub success: bool, pub events: Vec, } - -#[derive(Debug, Display)] -pub enum ListEventsError { - ServerError, -} - -impl ResponseError for ListEventsError { - fn status_code(&self) -> StatusCode { - match *self { - ListEventsError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListEventsError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - pub async fn list_events_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { // NB: Since this is publicly exposed, we don't query sensitive data. let events = list_public_event_feed_items(&server_state.mysql_pool) .await .map_err(|err| { error!("error querying for event feed events: {:?}", err); - ListEventsError::ServerError + CommonWebError::from_anyhow_error(err) })? .into_iter() .map(|event| { @@ -131,7 +110,7 @@ pub async fn list_events_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListEventsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/media_uploads/list_user_media_uploads_of_type.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/media_uploads/list_user_media_uploads_of_type.rs index 15a1126c0d..5df5d6218c 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/media_uploads/list_user_media_uploads_of_type.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/media_uploads/list_user_media_uploads_of_type.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use log::warn; use crate::http_server::session::lookup::user_session_extended::UserSessionExtended; +use crate::http_server::common_responses::common_web_error::CommonWebError; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; use enums::common::visibility::Visibility; use mysql_queries::queries::media_uploads::reverse_list_user_media_uploads_of_type::reverse_list_user_media_uploads_of_type_with_connection; @@ -48,52 +49,20 @@ pub struct MediaUploadEntry { pub created_at: DateTime, pub updated_at: DateTime, } - -#[deprecated(note = "Use `media_files` instead of `media_uploads`.")] -#[derive(Debug)] -pub enum ListUserMediaUploadsOfTypeError { - ServerError, - NotAuthorized, -} - -impl ResponseError for ListUserMediaUploadsOfTypeError { - fn status_code(&self) -> StatusCode { - match *self { - Self::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - Self::NotAuthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - Self::ServerError => "server error".to_string(), - Self::NotAuthorized => "not authorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListUserMediaUploadsOfTypeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - #[deprecated(note = "Use `media_files` instead of `media_uploads`.")] pub async fn list_user_media_uploads_of_type_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result +) -> Result { let mut mysql_connection = server_state.mysql_pool .acquire() .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - ListUserMediaUploadsOfTypeError::ServerError + CommonWebError::from_error(err) })?; // ==================== USER SESSION ==================== // @@ -104,12 +73,12 @@ pub async fn list_user_media_uploads_of_type_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListUserMediaUploadsOfTypeError::ServerError + CommonWebError::from_error(e) })?; let user_token = match maybe_user_session { None => { - return Err(ListUserMediaUploadsOfTypeError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } Some(user_session) => UserToken::new_from_str(&user_session.user_token), }; @@ -124,7 +93,7 @@ pub async fn list_user_media_uploads_of_type_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListUserMediaUploadsOfTypeError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -143,7 +112,7 @@ pub async fn list_user_media_uploads_of_type_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListUserMediaUploadsOfTypeError::ServerError)?; + .map_err(|e| CommonWebError::from_error(e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/delete_category.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/delete_category.rs index ad0befc230..20f612c8d4 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/delete_category.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/delete_category.rs @@ -11,6 +11,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::model_categories::toggle_model_category_soft_delete::{toggle_model_category_soft_delete, ToggleSoftDeleteState}; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -33,42 +34,14 @@ pub struct DeleteCategoryResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum DeleteCategoryError { - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for DeleteCategoryError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteCategoryError::NotFound => StatusCode::NOT_FOUND, - DeleteCategoryError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteCategoryError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for DeleteCategoryError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn delete_category_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -76,21 +49,21 @@ pub async fn delete_category_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteCategoryError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteCategoryError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: We don't have a permission for categories, so we use this as a proxy. if !user_session.can_ban_users { warn!("no permission to delete categories"); - return Err(DeleteCategoryError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let soft_delete_state = if request.set_delete { @@ -109,7 +82,7 @@ pub async fn delete_category_handler( Ok(_) => {}, Err(err) => { warn!("Delete/undelete category edit DB error: {:?}", err); - return Err(DeleteCategoryError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -118,7 +91,7 @@ pub async fn delete_category_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| DeleteCategoryError::ServerError)?; + ?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/edit_category.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/edit_category.rs index 94f697dff8..fdeb0d2717 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/edit_category.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/edit_category.rs @@ -12,6 +12,7 @@ use mysql_queries::queries::model_categories::get_category_by_token::get_categor use mysql_queries::queries::model_categories::update_model_category::{update_model_category, UpdateModelCategoryArgs}; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -50,44 +51,14 @@ pub struct EditCategoryResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum EditCategoryError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for EditCategoryError { - fn status_code(&self) -> StatusCode { - match *self { - EditCategoryError::BadInput(_) => StatusCode::BAD_REQUEST, - EditCategoryError::NotFound => StatusCode::NOT_FOUND, - EditCategoryError::NotAuthorized => StatusCode::UNAUTHORIZED, - EditCategoryError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditCategoryError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn edit_category_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -95,27 +66,27 @@ pub async fn edit_category_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - EditCategoryError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(EditCategoryError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: We don't have a permission for categories, so we use this as a proxy. if !user_session.can_ban_users { warn!("no permission to edit categories"); - return Err(EditCategoryError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } // Category tree integrity if let Some(parent_category_token) = request.maybe_super_category_token.as_deref() { if parent_category_token == &path.token { - return Err(EditCategoryError::BadInput( + return Err(CommonWebError::BadInputWithSimpleMessage( "category cannot have itself as a parent".to_string())); } @@ -125,14 +96,14 @@ pub async fn edit_category_handler( match parent_category_lookup { Ok(Some(parent_category)) => { if !parent_category.can_have_subcategories { - return Err(EditCategoryError::BadInput( + return Err(CommonWebError::BadInputWithSimpleMessage( "parent category cannot have children".to_string())); } }, - Ok(None) => return Err(EditCategoryError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { warn!("Category lookup DB error: {:?}", err); - return Err(EditCategoryError::ServerError) + return Err(CommonWebError::from_anyhow_error(err)) }, } } @@ -155,7 +126,7 @@ pub async fn edit_category_handler( Ok(_) => {}, Err(err) => { warn!("Edit category DB error: {:?}", err); - return Err(EditCategoryError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -164,7 +135,7 @@ pub async fn edit_category_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| EditCategoryError::ServerError)?; + ?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/list_tts_categories_for_moderation.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/list_tts_categories_for_moderation.rs index da15c40580..f83d40dacb 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/list_tts_categories_for_moderation.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/categories/list_tts_categories_for_moderation.rs @@ -11,6 +11,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::model_categories::list_categories_query_builder::ListCategoriesQueryBuilder; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -70,39 +71,13 @@ pub struct CategoryForModeration { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum ListTtsCategoriesForModerationError { - NotAuthorized, - ServerError, -} - -impl ResponseError for ListTtsCategoriesForModerationError { - fn status_code(&self) -> StatusCode { - match *self { - ListTtsCategoriesForModerationError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListTtsCategoriesForModerationError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTtsCategoriesForModerationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn list_tts_categories_for_moderation_handler( http_request: HttpRequest, query: web::Query, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -110,21 +85,21 @@ pub async fn list_tts_categories_for_moderation_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListTtsCategoriesForModerationError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ListTtsCategoriesForModerationError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: We don't have a permission for categories, so we use this as a proxy. if !user_session.can_ban_users { warn!("no permission to edit categories"); - return Err(ListTtsCategoriesForModerationError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } // The objects we'll show or hide @@ -153,7 +128,7 @@ pub async fn list_tts_categories_for_moderation_handler( Ok(results) => results, Err(err) => { warn!("DB error: {:?}", err); - return Err(ListTtsCategoriesForModerationError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -192,7 +167,7 @@ pub async fn list_tts_categories_for_moderation_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListTtsCategoriesForModerationError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_on_prem_worker_stats.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_on_prem_worker_stats.rs index cd98766910..bfc9d48c8e 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_on_prem_worker_stats.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_on_prem_worker_stats.rs @@ -7,6 +7,7 @@ use log::warn; use mysql_queries::queries::stats::get_on_prem_worker_stats::get_on_prem_worker_stats; use crate::http_server::web_utils::serialize_as_json_error::serialize_as_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; const MIN_SAMPLE_SIZE : u32 = 100; @@ -31,38 +32,12 @@ pub struct WorkerMixStats { pub on_prem_count: i64, pub cloud_count: i64, } - -#[derive(Debug, Serialize)] -pub enum GetOnPremWorkerStatsError { - ServerError, - Unauthorized, -} - -impl ResponseError for GetOnPremWorkerStatsError { - fn status_code(&self) -> StatusCode { - match *self { - GetOnPremWorkerStatsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetOnPremWorkerStatsError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl std::fmt::Display for GetOnPremWorkerStatsError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_on_prem_worker_stats_handler( http_request: HttpRequest, query: Query, server_state: web::Data>, -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -70,21 +45,21 @@ pub async fn get_on_prem_worker_stats_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetOnPremWorkerStatsError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(GetOnPremWorkerStatsError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: Not a good fit for this permission. if !user_session.can_edit_other_users_tts_models { warn!("user is not allowed to edit user tts: {:?}", user_session.user_token); - return Err(GetOnPremWorkerStatsError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let sample_size = query.sample_size @@ -97,7 +72,7 @@ pub async fn get_on_prem_worker_stats_handler( ) .await .map_err(|e| { - GetOnPremWorkerStatsError::ServerError + CommonWebError::from_anyhow_error(e) })?; let response = GetOnPremWorkerStatsResponse { @@ -110,7 +85,7 @@ pub async fn get_on_prem_worker_stats_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetOnPremWorkerStatsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_voice_count_stats.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_voice_count_stats.rs index 9a46535770..b713253f74 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_voice_count_stats.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/stats/get_voice_count_stats.rs @@ -8,6 +8,7 @@ use log::warn; use mysql_queries::queries::stats::get_voice_count_stats::get_voice_count_stats; use crate::http_server::web_utils::serialize_as_json_error::serialize_as_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -16,37 +17,11 @@ pub struct GetVoiceCountStatsResponse { pub all_voices_count_including_deleted: i64, pub public_voices_count: i64, } - -#[derive(Debug, Serialize)] -pub enum GetVoiceCountStatsError { - ServerError, - Unauthorized, -} - -impl ResponseError for GetVoiceCountStatsError { - fn status_code(&self) -> StatusCode { - match *self { - GetVoiceCountStatsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetVoiceCountStatsError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl std::fmt::Display for GetVoiceCountStatsError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_voice_count_stats_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -54,27 +29,27 @@ pub async fn get_voice_count_stats_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetVoiceCountStatsError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(GetVoiceCountStatsError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: Not a good fit for this permission. if !user_session.can_edit_other_users_tts_models { warn!("user is not allowed to edit user tts: {:?}", user_session.user_token); - return Err(GetVoiceCountStatsError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let result = get_voice_count_stats(&server_state.mysql_pool) .await .map_err(|e| { - GetVoiceCountStatsError::ServerError + CommonWebError::from_anyhow_error(e) })?; let response = GetVoiceCountStatsResponse { @@ -84,7 +59,7 @@ pub async fn get_voice_count_stats_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetVoiceCountStatsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_roles.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_roles.rs index ce2de96df1..f240ebed35 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_roles.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_roles.rs @@ -9,6 +9,7 @@ use log::warn; use mysql_queries::queries::users::user_roles::list_user_roles::{list_user_roles, UserRoleForList}; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -16,45 +17,11 @@ pub struct ListUserRolesResponse { pub success: bool, pub user_roles: Vec, } - -#[derive(Debug)] -pub enum ListUserRolesError { - BadInput(String), - ServerError, - Unauthorized, -} - -impl ResponseError for ListUserRolesError { - fn status_code(&self) -> StatusCode { - match *self { - ListUserRolesError::BadInput(_) => StatusCode::BAD_REQUEST, - ListUserRolesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - ListUserRolesError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListUserRolesError::BadInput(reason) => reason.to_string(), - ListUserRolesError::ServerError => "server error".to_string(), - ListUserRolesError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListUserRolesError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_user_roles_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -62,21 +29,21 @@ pub async fn list_user_roles_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListUserRolesError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ListUserRolesError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: Add new permission for this. if !user_session.can_ban_users { warn!("user is not allowed to view user roles: {:?}", user_session.user_token); - return Err(ListUserRolesError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let maybe_user_roles = @@ -86,7 +53,7 @@ pub async fn list_user_roles_handler( Ok(results) => results, Err(e) => { warn!("Error querying user roles: {:?}", e); - return Err(ListUserRolesError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -96,7 +63,7 @@ pub async fn list_user_roles_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListUserRolesError::ServerError)?; + .map_err(|e| CommonWebError::from_error(e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_staff.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_staff.rs index 2ae6d3c7f3..e4df05f93f 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_staff.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/list_staff.rs @@ -9,6 +9,7 @@ use log::{error, warn}; use mysql_queries::queries::users::user_roles::list_staff::list_staff; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -25,38 +26,10 @@ pub struct StaffRecordForList { pub user_role_slug: String, pub user_role_name: String, } - -#[derive(Debug, Display)] -pub enum ListStaffError { - BadInput(String), - ServerError, - Unauthorized, -} - -impl ResponseError for ListStaffError { - fn status_code(&self) -> StatusCode { - match *self { - ListStaffError::BadInput(_) => StatusCode::BAD_REQUEST, - ListStaffError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - ListStaffError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListStaffError::BadInput(reason) => reason.to_string(), - ListStaffError::ServerError => "server error".to_string(), - ListStaffError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - pub async fn list_staff_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -64,28 +37,28 @@ pub async fn list_staff_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListStaffError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ListStaffError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: This is not the correct permission. if !user_session.can_ban_users { warn!("user is not allowed to delete bans: {:?}", user_session.user_token); - return Err(ListStaffError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let results = list_staff(&server_state.mysql_pool) .await .map_err(|err| { error!("list staff db error: {:?}", err); - ListStaffError::ServerError + CommonWebError::from_anyhow_error(err) })? .into_iter() .map(|user| StaffRecordForList { @@ -103,7 +76,7 @@ pub async fn list_staff_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListStaffError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/set_user_role.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/set_user_role.rs index 63f1f53926..7624c807f2 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/set_user_role.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/moderation/user_roles/set_user_role.rs @@ -12,6 +12,7 @@ use mysql_queries::queries::users::user_roles::list_user_roles::list_user_roles; use mysql_queries::queries::users::user_roles::set_user_role::set_user_role; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; @@ -25,49 +26,12 @@ pub struct SetUserRolePathInfo { pub struct SetUserRoleRequest { user_role_slug: String, } - -#[derive(Debug)] -pub enum SetUserRoleError { - BadInput(String), - NotAuthorized, - NotFound, - ServerError, -} - -impl ResponseError for SetUserRoleError { - fn status_code(&self) -> StatusCode { - match *self { - SetUserRoleError::BadInput(_) => StatusCode::BAD_REQUEST, - SetUserRoleError::NotAuthorized => StatusCode::UNAUTHORIZED, - SetUserRoleError::NotFound => StatusCode::NOT_FOUND, - SetUserRoleError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - SetUserRoleError::BadInput(reason) => reason.to_string(), - SetUserRoleError::NotAuthorized => "unauthorized".to_string(), - SetUserRoleError::NotFound => "not found".to_string(), - SetUserRoleError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for SetUserRoleError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn set_user_role_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -75,21 +39,21 @@ pub async fn set_user_role_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - SetUserRoleError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(SetUserRoleError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: This is not the correct permission if !user_session.can_ban_users { warn!("user is not allowed to change user roles: {:?}", user_session.user_token); - return Err(SetUserRoleError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } // TODO: This is lazy and inefficient @@ -97,7 +61,7 @@ pub async fn set_user_role_handler( .await .map_err(|err| { warn!("error listing roles: {:?}", err); - SetUserRoleError::ServerError + CommonWebError::from_anyhow_error(err) })?; let role_exists = user_roles.into_iter() @@ -105,7 +69,7 @@ pub async fn set_user_role_handler( .is_some(); if !role_exists { - return Err(SetUserRoleError::BadInput("invalid user role".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid user role".to_string())); } let user_lookup_result = @@ -113,10 +77,10 @@ pub async fn set_user_role_handler( let target_user = match user_lookup_result { Ok(Some(result)) => result, - Ok(None) => return Err(SetUserRoleError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { warn!("lookup error: {:?}", err); - return Err(SetUserRoleError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -130,7 +94,7 @@ pub async fn set_user_role_handler( Ok(_) => {}, Err(err) => { warn!("unable to update user role: {:?}", err); - return Err(SetUserRoleError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_model_downloads.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_model_downloads.rs index a6bab2cdc2..f0d8470e50 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_model_downloads.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_model_downloads.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Success Response =============== @@ -40,36 +41,12 @@ pub struct AppModelDownloadsResponse { // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum AppModelDownloadsError { - ServerError, -} - -impl ResponseError for AppModelDownloadsError { - fn status_code(&self) -> StatusCode { - match *self { - AppModelDownloadsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for AppModelDownloadsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn get_app_model_downloads_handler( http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { // TODO: Real news items. @@ -95,7 +72,7 @@ pub async fn get_app_model_downloads_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| AppModelDownloadsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_news.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_news.rs index c29fb66469..7543e472df 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_news.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_news.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Success Response =============== @@ -37,36 +38,12 @@ pub struct AppNewsResponse { // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum AppNewsError { - ServerError, -} - -impl ResponseError for AppNewsError { - fn status_code(&self) -> StatusCode { - match *self { - AppNewsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for AppNewsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn get_app_news_handler( http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { // TODO: Real news items. @@ -97,7 +74,7 @@ pub async fn get_app_news_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| AppNewsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_plans.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_plans.rs index bc9b1ffe9a..b58a665e54 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_plans.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/app_plans.rs @@ -10,6 +10,7 @@ use enums::common::payments_namespace::PaymentsNamespace; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Success Response =============== @@ -53,36 +54,12 @@ pub struct AppFeature { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum AppPlansError { - ServerError, -} - -impl ResponseError for AppPlansError { - fn status_code(&self) -> StatusCode { - match *self { - AppPlansError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for AppPlansError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn get_app_plans_handler( http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user = server_state .session_checker @@ -90,7 +67,7 @@ pub async fn get_app_plans_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - AppPlansError::ServerError + CommonWebError::from_error(e) })?; let unlimited_time = maybe_user @@ -155,7 +132,7 @@ pub async fn get_app_plans_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| AppPlansError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/post_app_analytics.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/post_app_analytics.rs index b97994e438..651ab1c2e5 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/post_app_analytics.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/stubs/post_app_analytics.rs @@ -10,6 +10,7 @@ use http_server_common::request::get_request_ip::get_request_ip; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -75,41 +76,13 @@ pub struct PostAppAnalyticsResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum PostAppAnalyticsError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for PostAppAnalyticsError { - fn status_code(&self) -> StatusCode { - match *self { - PostAppAnalyticsError::BadInput(_) => StatusCode::BAD_REQUEST, - PostAppAnalyticsError::NotAuthorized => StatusCode::UNAUTHORIZED, - PostAppAnalyticsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for PostAppAnalyticsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn post_app_analytics_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -117,7 +90,7 @@ pub async fn post_app_analytics_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - PostAppAnalyticsError::ServerError + CommonWebError::from_error(e) })?; let creator_ip_address = get_request_ip(&http_request); @@ -129,7 +102,7 @@ pub async fn post_app_analytics_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| PostAppAnalyticsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/get_vocoder.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/get_vocoder.rs index edd3c11b3c..00ecdef31e 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/get_vocoder.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/get_vocoder.rs @@ -3,11 +3,8 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Path; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; @@ -17,7 +14,7 @@ use enums::common::visibility::Visibility; use enums::common::vocoder_type::VocoderType; use mysql_queries::queries::vocoder::get_vocoder_model::get_vocoder_model_by_token; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; // =============== Request =============== @@ -77,43 +74,12 @@ pub struct VocoderModFields { } // =============== Error Response =============== - -#[derive(Debug)] -pub enum GetVocoderError { - NotFound, - ServerError, -} - -impl ResponseError for GetVocoderError { - fn status_code(&self) -> StatusCode { - match *self { - GetVocoderError::NotFound => StatusCode::NOT_FOUND, - GetVocoderError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetVocoderError::NotFound => "not found".to_string(), - GetVocoderError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetVocoderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_vocoder_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result { +) -> Result { let is_moderator = server_state .session_checker @@ -121,7 +87,7 @@ pub async fn get_vocoder_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetVocoderError::ServerError + CommonWebError::from_error(e) })? .map(|session| { // NB: Since we need to rip out and replace the permissions system, @@ -140,10 +106,10 @@ pub async fn get_vocoder_handler( let vocoder = match query_result { Ok(Some(model)) => model, - Ok(None) => return Err(GetVocoderError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(e) => { warn!("query error: {:?}", e); - return Err(GetVocoderError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -185,7 +151,7 @@ pub async fn get_vocoder_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| GetVocoderError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/list_vocoders.rs b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/list_vocoders.rs index 50976c6b61..afb7098824 100644 --- a/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/list_vocoders.rs +++ b/crates/service/web/storyteller_web/src/http_server/deprecated_endpoints/vocoders/list_vocoders.rs @@ -3,11 +3,8 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use log::warn; @@ -15,7 +12,7 @@ use log::warn; use enums::common::vocoder_type::VocoderType; use mysql_queries::queries::vocoder::list_vocoder_models::{list_vocoder_models, VocoderModelListItem}; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -53,40 +50,11 @@ pub struct VocoderListItemModFields { pub user_deleted_at: Option>, pub mod_deleted_at: Option>, } - - -#[derive(Debug)] -pub enum ListVocodersError { - ServerError, -} - -impl ResponseError for ListVocodersError { - fn status_code(&self) -> StatusCode { - match *self { - ListVocodersError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListVocodersError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListVocodersError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_vocoders_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let is_moderator = server_state .session_checker @@ -94,7 +62,7 @@ pub async fn list_vocoders_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListVocodersError::ServerError + CommonWebError::from_error(e) })? .map(|session| { // NB: Since we need to rip out and replace the permissions system, @@ -115,7 +83,7 @@ pub async fn list_vocoders_handler( Ok(results) => results, Err(e) => { warn!("vocoder list query error: {:?}", e); - return Err(ListVocodersError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -156,7 +124,7 @@ pub async fn list_vocoders_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ListVocodersError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/create_beta_keys_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/create_beta_keys_handler.rs index 4100ed3075..d2e2a70177 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/create_beta_keys_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/create_beta_keys_handler.rs @@ -13,6 +13,7 @@ use mysql_queries::queries::beta_keys::insert_batch_beta_keys::{insert_batch_bet use mysql_queries::queries::users::user_profiles::get_user_profile_by_username::get_user_profile_by_username; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_moderator::{require_moderator, RequireModeratorError, UseDatabase}; use crate::state::server_state::ServerState; @@ -37,41 +38,7 @@ pub struct CreateBetaKeysSuccessResponse { pub success: bool, pub beta_keys: Vec, } - -#[derive(Debug, ToSchema)] -pub enum CreateBetaKeysError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CreateBetaKeysError { - fn status_code(&self) -> StatusCode { - match *self { - CreateBetaKeysError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateBetaKeysError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateBetaKeysError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - CreateBetaKeysError::BadInput(reason) => reason.to_string(), - CreateBetaKeysError::NotAuthorized => "unauthorized".to_string(), - CreateBetaKeysError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for CreateBetaKeysError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Create beta keys in bulk, and possibly assign them to a referrer user. #[utoipa::path( post, @@ -79,9 +46,9 @@ impl fmt::Display for CreateBetaKeysError { path = "/v1/beta_keys/create", responses( (status = 200, description = "Success", body = CreateBetaKeysSuccessResponse), - (status = 400, description = "Bad input", body = CreateBetaKeysError), - (status = 401, description = "Not authorized", body = CreateBetaKeysError), - (status = 500, description = "Server error", body = CreateBetaKeysError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = CreateBetaKeysRequest, description = "Payload for Request"), @@ -91,13 +58,13 @@ pub async fn create_beta_keys_handler( http_request: HttpRequest, request: web::Json, server_state: web::Data>, -) -> Result +) -> Result { let user_session = require_moderator(&http_request, &server_state, UseDatabase::GrabNewConnection) .await .map_err(|err| match err { - RequireModeratorError::ServerError => CreateBetaKeysError::ServerError, - RequireModeratorError::NotAuthorized => CreateBetaKeysError::NotAuthorized, + RequireModeratorError::ServerError => CommonWebError::from_error(err), + RequireModeratorError::NotAuthorized => CommonWebError::NotAuthorized, })?; let mut maybe_referrer_user_token = None; @@ -108,13 +75,13 @@ pub async fn create_beta_keys_handler( .await .map_err(|err| { warn!("Error inserting beta keys: {:?}", err); - CreateBetaKeysError::ServerError + CommonWebError::from_anyhow_error(err) })?; let user = match maybe_user { Some(user) => user, None => { - return Err(CreateBetaKeysError::BadInput("referrer user not found".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("referrer user not found".to_string())); } }; @@ -136,7 +103,7 @@ pub async fn create_beta_keys_handler( mysql_pool: &server_state.mysql_pool, }).await.map_err(|err| { warn!("Error inserting beta keys: {:?}", err); - CreateBetaKeysError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = CreateBetaKeysSuccessResponse { @@ -145,7 +112,7 @@ pub async fn create_beta_keys_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| CreateBetaKeysError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_distributed_flag_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_distributed_flag_handler.rs index a39c1c6308..9a98730c68 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_distributed_flag_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_distributed_flag_handler.rs @@ -13,6 +13,7 @@ use tokens::tokens::beta_keys::BetaKeyToken; use tokens::tokens::w2l_results::W2lResultToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_moderator::{require_moderator, RequireModeratorError, UseDatabase}; use crate::state::server_state::ServerState; @@ -33,41 +34,7 @@ pub struct EditBetaKeyDistributedFlagRequest { pub struct EditBetaKeyDistributedFlagSuccessResponse { pub success: bool, } - -#[derive(Debug, ToSchema)] -pub enum EditBetaKeyDistributedFlagError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for EditBetaKeyDistributedFlagError { - fn status_code(&self) -> StatusCode { - match *self { - EditBetaKeyDistributedFlagError::BadInput(_) => StatusCode::BAD_REQUEST, - EditBetaKeyDistributedFlagError::NotAuthorized => StatusCode::UNAUTHORIZED, - EditBetaKeyDistributedFlagError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - EditBetaKeyDistributedFlagError::BadInput(reason) => reason.to_string(), - EditBetaKeyDistributedFlagError::NotAuthorized => "unauthorized".to_string(), - EditBetaKeyDistributedFlagError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditBetaKeyDistributedFlagError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Edit the "distributed" flag on a beta key to mark it as shared #[utoipa::path( post, @@ -75,9 +42,9 @@ impl fmt::Display for EditBetaKeyDistributedFlagError { path = "/v1/beta_keys/{token}/distributed", responses( (status = 200, description = "Success", body = EditBetaKeyDistributedFlagSuccessResponse), - (status = 400, description = "Bad input", body = EditBetaKeyDistributedFlagError), - (status = 401, description = "Not authorized", body = EditBetaKeyDistributedFlagError), - (status = 500, description = "Server error", body = EditBetaKeyDistributedFlagError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = EditBetaKeyDistributedFlagRequest, description = "Payload for Request"), @@ -89,20 +56,20 @@ pub async fn edit_beta_key_distributed_flag_handler( request: web::Json, path: Path, server_state: web::Data>, -) -> Result +) -> Result { let user_session = require_moderator(&http_request, &server_state, UseDatabase::GrabNewConnection) .await .map_err(|err| match err { - RequireModeratorError::ServerError => EditBetaKeyDistributedFlagError::ServerError, - RequireModeratorError::NotAuthorized => EditBetaKeyDistributedFlagError::NotAuthorized, + RequireModeratorError::ServerError => CommonWebError::from_error(err), + RequireModeratorError::NotAuthorized => CommonWebError::NotAuthorized, })?; edit_beta_key_distributed_flag(&path.token, request.is_distributed, &server_state.mysql_pool) .await .map_err(|err| { warn!("Error editing beta key note: {:?}", err); - EditBetaKeyDistributedFlagError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = EditBetaKeyDistributedFlagSuccessResponse { @@ -110,7 +77,7 @@ pub async fn edit_beta_key_distributed_flag_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| EditBetaKeyDistributedFlagError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_note_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_note_handler.rs index 0cdfc3dac1..1cba9f8156 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_note_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/edit_beta_key_note_handler.rs @@ -12,6 +12,7 @@ use mysql_queries::queries::beta_keys::edit_beta_key_note::edit_beta_key_note; use tokens::tokens::beta_keys::BetaKeyToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_moderator::{require_moderator, RequireModeratorError, UseDatabase}; use crate::state::server_state::ServerState; @@ -32,41 +33,7 @@ pub struct EditBetaKeyNoteRequest { pub struct EditBetaKeyNoteSuccessResponse { pub success: bool, } - -#[derive(Debug, ToSchema)] -pub enum EditBetaKeyNoteError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for EditBetaKeyNoteError { - fn status_code(&self) -> StatusCode { - match *self { - EditBetaKeyNoteError::BadInput(_) => StatusCode::BAD_REQUEST, - EditBetaKeyNoteError::NotAuthorized => StatusCode::UNAUTHORIZED, - EditBetaKeyNoteError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - EditBetaKeyNoteError::BadInput(reason) => reason.to_string(), - EditBetaKeyNoteError::NotAuthorized => "unauthorized".to_string(), - EditBetaKeyNoteError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditBetaKeyNoteError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Edit or clear a note on a beta key #[utoipa::path( post, @@ -74,9 +41,9 @@ impl fmt::Display for EditBetaKeyNoteError { path = "/v1/beta_keys/{token}/note", responses( (status = 200, description = "Success", body = EditBetaKeyNoteSuccessResponse), - (status = 400, description = "Bad input", body = EditBetaKeyNoteError), - (status = 401, description = "Not authorized", body = EditBetaKeyNoteError), - (status = 500, description = "Server error", body = EditBetaKeyNoteError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = EditBetaKeyNoteRequest, description = "Payload for Request"), @@ -88,13 +55,13 @@ pub async fn edit_beta_key_note_handler( request: web::Json, path: Path, server_state: web::Data>, -) -> Result +) -> Result { let user_session = require_moderator(&http_request, &server_state, UseDatabase::GrabNewConnection) .await .map_err(|err| match err { - RequireModeratorError::ServerError => EditBetaKeyNoteError::ServerError, - RequireModeratorError::NotAuthorized => EditBetaKeyNoteError::NotAuthorized, + RequireModeratorError::ServerError => CommonWebError::from_error(err), + RequireModeratorError::NotAuthorized => CommonWebError::NotAuthorized, })?; let maybe_note = request.note.as_deref() @@ -106,7 +73,7 @@ pub async fn edit_beta_key_note_handler( .await .map_err(|err| { warn!("Error editing beta key note: {:?}", err); - EditBetaKeyNoteError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = EditBetaKeyNoteSuccessResponse { @@ -114,7 +81,7 @@ pub async fn edit_beta_key_note_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| EditBetaKeyNoteError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/list_beta_keys_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/list_beta_keys_handler.rs index 3683ac46ad..392ceed61b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/list_beta_keys_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/beta_keys/list_beta_keys_handler.rs @@ -15,6 +15,7 @@ use mysql_queries::queries::users::user_profiles::get_user_profile_by_username:: use tokens::tokens::beta_keys::BetaKeyToken; use crate::http_server::common_responses::pagination_page::PaginationPage; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::web_utils::user_session::require_user_session::{require_user_session, RequireUserSessionError}; use crate::state::server_state::ServerState; @@ -88,30 +89,6 @@ pub struct BetaKeyItem { /// When the key was redeemed (the key will no longer be usable once redeemed) pub maybe_redeemed_at: Option>, } - -#[derive(Debug, ToSchema)] -pub enum ListBetaKeysError { - BadRequest(String), - NotAuthorized, - ServerError, -} - -impl std::fmt::Display for ListBetaKeysError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for ListBetaKeysError { - fn status_code(&self) -> StatusCode { - match *self { - ListBetaKeysError::BadRequest(_)=> StatusCode::BAD_REQUEST, - ListBetaKeysError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListBetaKeysError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - /// List beta keys. #[utoipa::path( get, @@ -122,20 +99,20 @@ impl ResponseError for ListBetaKeysError { ), responses( (status = 200, description = "List Featured Media Files", body = ListBetaKeysSuccessResponse), - (status = 401, description = "Not authorized", body = ListBetaKeysError), - (status = 500, description = "Server error", body = ListBetaKeysError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn list_beta_keys_handler( http_request: HttpRequest, query: Query, server_state: web::Data> -) -> Result { +) -> Result { let user_session = require_user_session(&http_request, &server_state) .await .map_err(|err| match err { - RequireUserSessionError::ServerError => ListBetaKeysError::ServerError, - RequireUserSessionError::NotAuthorized => ListBetaKeysError::NotAuthorized, + RequireUserSessionError::ServerError => CommonWebError::from_error(err), + RequireUserSessionError::NotAuthorized => CommonWebError::NotAuthorized, })?; let mut is_mod = user_session.can_ban_users; @@ -152,11 +129,11 @@ pub async fn list_beta_keys_handler( .await .map_err(|e| { warn!("get user profile error: {:?}", e); - ListBetaKeysError::ServerError + CommonWebError::from_anyhow_error(e) })?; match maybe_referrer_user { - None => return Err(ListBetaKeysError::BadRequest("referrer user not found".to_string())), + None => return Err(CommonWebError::BadInputWithSimpleMessage("referrer user not found".to_string())), Some(user) => { maybe_scope_user_token = Some(user.user_token.clone()); }, @@ -193,7 +170,7 @@ pub async fn list_beta_keys_handler( Ok(results) => results, Err(err) => { warn!("Query error: {:?}", err); - return Err(ListBetaKeysError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -240,7 +217,7 @@ pub async fn list_beta_keys_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListBetaKeysError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/create_featured_item_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/create_featured_item_handler.rs index 38ee4bcd58..f631e36c77 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/create_featured_item_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/create_featured_item_handler.rs @@ -23,6 +23,7 @@ use tokens::tokens::users::UserToken; use tokens::tokens::w2l_templates::W2lTemplateToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Deserialize, ToSchema)] @@ -35,41 +36,7 @@ pub struct CreateFeaturedItemRequest { pub struct CreateFeaturedItemSuccessResponse { pub success: bool, } - -#[derive(Debug, ToSchema)] -pub enum CreateFeaturedItemError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CreateFeaturedItemError { - fn status_code(&self) -> StatusCode { - match *self { - CreateFeaturedItemError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateFeaturedItemError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateFeaturedItemError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - CreateFeaturedItemError::BadInput(reason) => reason.to_string(), - CreateFeaturedItemError::NotAuthorized => "unauthorized".to_string(), - CreateFeaturedItemError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for CreateFeaturedItemError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Create a featured item (only mods can do this). #[utoipa::path( post, @@ -78,14 +45,14 @@ impl fmt::Display for CreateFeaturedItemError { request_body = CreateFeaturedItemRequest, responses( (status = 200, body = CreateFeaturedItemSuccessResponse), - (status = 400, body = CreateFeaturedItemError), + (status = 400, body = CommonWebError), ) )] pub async fn create_featured_item_handler( http_request: HttpRequest, request: web::Json, server_state: web::Data>, -) -> Result +) -> Result { // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from // querying the database for entity existence, this is the next best way to prevent incorrect comment @@ -100,7 +67,7 @@ pub async fn create_featured_item_handler( if !token_prefix_matches { warn!("invalid token prefix: {:?} for {:?}", request.entity_token, request.entity_type); - return Err(CreateFeaturedItemError::BadInput("invalid token prefix".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid token prefix".to_string())); } let mut mysql_connection = server_state.mysql_pool @@ -108,7 +75,7 @@ pub async fn create_featured_item_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - CreateFeaturedItemError::ServerError + CommonWebError::from_error(err) })?; let maybe_user_session = server_state @@ -117,14 +84,14 @@ pub async fn create_featured_item_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - CreateFeaturedItemError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(CreateFeaturedItemError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -132,7 +99,7 @@ pub async fn create_featured_item_handler( if !is_mod { warn!("not moderator"); - return Err(CreateFeaturedItemError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let entity = FeaturedItemEntity::from_entity_type_and_token( @@ -141,7 +108,7 @@ pub async fn create_featured_item_handler( let mut transaction = mysql_connection.begin().await .map_err(|err| { error!("error creating transaction: {:?}", err); - CreateFeaturedItemError::ServerError + CommonWebError::from_error(err) })?; match request.entity_type { @@ -155,7 +122,7 @@ pub async fn create_featured_item_handler( if let Err(err) = result { warn!("error modifying visibility: {:?}", err); - return Err(CreateFeaturedItemError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } } FeaturedItemEntityType::ModelWeight => {} // TODO @@ -170,7 +137,7 @@ pub async fn create_featured_item_handler( if let Err(err) = upsert_result { warn!("error setting featured: {:?}", err); - return Err(CreateFeaturedItemError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } let ip_address = get_request_ip(&http_request); @@ -189,7 +156,7 @@ pub async fn create_featured_item_handler( transaction.commit().await .map_err(|err| { error!("error committing transaction: {:?}", err); - CreateFeaturedItemError::ServerError + CommonWebError::from_error(err) })?; let response = CreateFeaturedItemSuccessResponse { @@ -197,7 +164,7 @@ pub async fn create_featured_item_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| CreateFeaturedItemError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/delete_featured_item_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/delete_featured_item_handler.rs index 98630dceb2..4ed891afb0 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/delete_featured_item_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/delete_featured_item_handler.rs @@ -21,6 +21,7 @@ use tokens::tokens::users::UserToken; use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; @@ -29,44 +30,7 @@ pub struct DeleteFeaturedItemRequest { entity_token: String, entity_type: FeaturedItemEntityType, } - -#[derive(Debug, ToSchema)] -pub enum DeleteFeaturedItemError { - BadInput(String), - NotAuthorized, - NotFound, - ServerError, -} - -impl ResponseError for DeleteFeaturedItemError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteFeaturedItemError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteFeaturedItemError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteFeaturedItemError::NotFound => StatusCode::NOT_FOUND, - DeleteFeaturedItemError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - DeleteFeaturedItemError::BadInput(reason) => reason.to_string(), - DeleteFeaturedItemError::NotAuthorized => "unauthorized".to_string(), - DeleteFeaturedItemError::NotFound => "not found".to_string(), - DeleteFeaturedItemError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteFeaturedItemError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Remove a featured item (only mods can do this). #[utoipa::path( delete, @@ -75,17 +39,17 @@ impl fmt::Display for DeleteFeaturedItemError { request_body = DeleteFeaturedItemRequest, responses( (status = 200, description = "Success", body = SimpleGenericJsonSuccess), - (status = 400, description = "Bad input", body = DeleteFeaturedItemError), - (status = 401, description = "Not authorized", body = DeleteFeaturedItemError), - (status = 404, description = "Not found", body = DeleteFeaturedItemError), - (status = 500, description = "Server error", body = DeleteFeaturedItemError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 404, description = "Not found", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn delete_featured_item_handler( http_request: HttpRequest, request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from // querying the database for entity existence, this is the next best way to prevent incorrect comment @@ -100,7 +64,7 @@ pub async fn delete_featured_item_handler( if !token_prefix_matches { warn!("invalid token prefix: {:?} for {:?}", request.entity_token, request.entity_type); - return Err(DeleteFeaturedItemError::BadInput("invalid token prefix".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid token prefix".to_string())); } let mut mysql_connection = server_state.mysql_pool @@ -108,7 +72,7 @@ pub async fn delete_featured_item_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - DeleteFeaturedItemError::ServerError + CommonWebError::from_error(err) })?; let maybe_user_session = server_state @@ -117,13 +81,13 @@ pub async fn delete_featured_item_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteFeaturedItemError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { - return Err(DeleteFeaturedItemError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -131,7 +95,7 @@ pub async fn delete_featured_item_handler( if !is_mod { warn!("not moderator"); - return Err(DeleteFeaturedItemError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let entity = FeaturedItemEntity::from_entity_type_and_token( @@ -140,7 +104,7 @@ pub async fn delete_featured_item_handler( let mut transaction = mysql_connection.begin().await .map_err(|err| { error!("error creating transaction: {:?}", err); - DeleteFeaturedItemError::ServerError + CommonWebError::from_error(err) })?; let delete_result = delete_featured_item( @@ -164,13 +128,13 @@ pub async fn delete_featured_item_handler( transaction.commit().await .map_err(|err| { error!("error committing transaction: {:?}", err); - DeleteFeaturedItemError::ServerError + CommonWebError::from_error(err) })?; match delete_result { Ok(_) => {}, Err(_err) => { - return Err(DeleteFeaturedItemError::ServerError); + return Err(CommonWebError::from_anyhow_error(_err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/get_is_featured_item_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/get_is_featured_item_handler.rs index 1eb042f3b3..72ee3b7bc6 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/get_is_featured_item_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/featured_items/get_is_featured_item_handler.rs @@ -17,6 +17,7 @@ use tokens::tokens::users::UserToken; use tokens::tokens::w2l_templates::W2lTemplateToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Deserialize, ToSchema)] @@ -30,41 +31,7 @@ pub struct GetIsFeaturedItemSuccessResponse { pub success: bool, pub is_featured: bool, } - -#[derive(Debug, ToSchema)] -pub enum GetIsFeaturedItemError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for GetIsFeaturedItemError { - fn status_code(&self) -> StatusCode { - match *self { - GetIsFeaturedItemError::BadInput(_) => StatusCode::BAD_REQUEST, - GetIsFeaturedItemError::NotAuthorized => StatusCode::UNAUTHORIZED, - GetIsFeaturedItemError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetIsFeaturedItemError::BadInput(reason) => reason.to_string(), - GetIsFeaturedItemError::NotAuthorized => "unauthorized".to_string(), - GetIsFeaturedItemError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetIsFeaturedItemError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Determine if an item is featured #[utoipa::path( get, @@ -73,14 +40,14 @@ impl fmt::Display for GetIsFeaturedItemError { request_body = GetIsFeaturedItemPathInfo, responses( (status = 200, body = GetIsFeaturedItemSuccessResponse), - (status = 400, body = GetIsFeaturedItemError), + (status = 400, body = CommonWebError), ) )] pub async fn get_is_featured_item_handler( http_request: HttpRequest, path: Path, server_state: web::Data>, -) -> Result, GetIsFeaturedItemError> +) -> Result, CommonWebError> { // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from // querying the database for entity existence, this is the next best way to prevent incorrect comment @@ -95,7 +62,7 @@ pub async fn get_is_featured_item_handler( if !token_prefix_matches { warn!("invalid token prefix: {:?} for {:?}", path.entity_token, path.entity_type); - return Err(GetIsFeaturedItemError::BadInput("invalid token prefix".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid token prefix".to_string())); } let entity = FeaturedItemEntity::from_entity_type_and_token(path.entity_type, &path.entity_token); @@ -104,7 +71,7 @@ pub async fn get_is_featured_item_handler( .await .map_err(|err| { warn!("MySql error: {:?}", err); - GetIsFeaturedItemError::ServerError + CommonWebError::from_anyhow_error(err) })?; Ok(Json(GetIsFeaturedItemSuccessResponse { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/image_studio/update_gpt_image_job_status_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/image_studio/update_gpt_image_job_status_handler.rs index 8da01926e1..eda6a50c60 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/image_studio/update_gpt_image_job_status_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/image_studio/update_gpt_image_job_status_handler.rs @@ -2,6 +2,7 @@ use std::fmt; use std::sync::Arc; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use actix_web::error::ResponseError; use actix_web::http::StatusCode; @@ -58,41 +59,7 @@ pub enum UpdatedJobStatus { pub struct UpdateGptImageJobStatusSuccessResponse { pub success: bool, } - -#[derive(Debug, ToSchema)] -pub enum UpdateGptImageJobStatusError { - ServerError, - NotFound, - NotAuthorized, -} - -impl ResponseError for UpdateGptImageJobStatusError { - fn status_code(&self) -> StatusCode { - match *self { - UpdateGptImageJobStatusError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - UpdateGptImageJobStatusError::NotFound => StatusCode::NOT_FOUND, - UpdateGptImageJobStatusError::NotAuthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - Self::ServerError => "server error".to_string(), - Self::NotFound => "not found".to_string(), - Self::NotAuthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for UpdateGptImageJobStatusError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// [INTERNAL ENDPOINT] Update a GPT Image generation job status. /// This is called by our internal infra, not users. Keep it guarded. /// We can do secrets-based auth later. @@ -102,7 +69,7 @@ impl fmt::Display for UpdateGptImageJobStatusError { path = "/v1/image_studio/update_job_status", responses( (status = 200, body = UpdateGptImageJobStatusSuccessResponse), - (status = 500, body = UpdateGptImageJobStatusError), + (status = 500, body = CommonWebError), ), params( ("request" = UpdateGptImageJobStatusRequest, description = "Request"), @@ -111,14 +78,14 @@ impl fmt::Display for UpdateGptImageJobStatusError { pub async fn update_gpt_image_job_status_handler( http_request: HttpRequest, request: Json, - server_state: web::Data>) -> Result, UpdateGptImageJobStatusError> + server_state: web::Data>) -> Result, CommonWebError> { //// TODO(bt,2024-06-16): Reuse connection //let mut mysql_connection = server_state.mysql_pool.acquire() // .await // .map_err(|e| { // warn!("Could not acquire DB pool: {:?}", e); - // UpdateGptImageJobStatusError::ServerError + // CommonWebError::from_error(e) // })?; let inference_job = get_inference_job_status( @@ -128,10 +95,10 @@ pub async fn update_gpt_image_job_status_handler( let inference_job = match inference_job { Ok(Some(record)) => record, - Ok(None) => return Err(UpdateGptImageJobStatusError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { error!("tts job query error: {:?}", err); - return Err(UpdateGptImageJobStatusError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -142,10 +109,10 @@ pub async fn update_gpt_image_job_status_handler( return Ok(Json(UpdateGptImageJobStatusSuccessResponse { success: true })) }, // TODO: Handle other states as terminal states? - //JobStatusPlus::CompleteFailure => return Err(UpdateGptImageJobStatusError::ServerError), + //JobStatusPlus::CompleteFailure => return Err(CommonWebError::from_error(err)), //JobStatusPlus::AttemptFailed => {} //JobStatusPlus::Dead => {} - //JobStatusPlus::CancelledByUser => return Err(UpdateGptImageJobStatusError::ServerError), + //JobStatusPlus::CancelledByUser => return Err(CommonWebError::from_error(err)), //JobStatusPlus::CancelledBySystem => {} _ => {} // Intentional fall through. } @@ -170,7 +137,7 @@ pub async fn update_gpt_image_job_status_handler( Ok(media_token) => media_token, Err(err) => { error!("Error uploading image: {:?}", err); - return Err(UpdateGptImageJobStatusError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; } @@ -182,7 +149,7 @@ pub async fn update_gpt_image_job_status_handler( .await .map_err(|err| { error!("Error updating job: {:?}", err); - UpdateGptImageJobStatusError::ServerError + CommonWebError::from_anyhow_error(err) })?; info!("Job record updated for job: {:?}", request.job_token); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/admin/kill_inference_jobs_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/admin/kill_inference_jobs_handler.rs index 45c8531491..fe57f09637 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/admin/kill_inference_jobs_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/admin/kill_inference_jobs_handler.rs @@ -14,6 +14,7 @@ use mysql_queries::queries::generic_inference::web::kill_generic_inference_jobs; use mysql_queries::queries::generic_inference::web::kill_generic_inference_jobs::{kill_generic_inference_jobs, KillGenericInferenceJobsArgs}; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; /// Only certain job statuses should be modified. #[derive(Copy, Clone, PartialEq, Eq, Hash, Deserialize)] @@ -46,43 +47,13 @@ pub struct KillInferenceJobsRequest { pub struct KillInferenceJobsResponse { pub success: bool, } - -#[derive(Debug, Serialize)] -pub enum KillInferenceJobsError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for KillInferenceJobsError { - fn status_code(&self) -> StatusCode { - match *self { - KillInferenceJobsError::BadInput(_) => StatusCode::BAD_REQUEST, - KillInferenceJobsError::NotFound => StatusCode::NOT_FOUND, - KillInferenceJobsError::NotAuthorized => StatusCode::UNAUTHORIZED, - KillInferenceJobsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for KillInferenceJobsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn kill_generic_inference_jobs_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -90,21 +61,21 @@ pub async fn kill_generic_inference_jobs_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - KillInferenceJobsError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(KillInferenceJobsError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: We don't have a permission for this, so use this as a proxy permission if !user_session.can_ban_users { warn!("no permission to edit categories"); - return Err(KillInferenceJobsError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let job_statuses = request.job_statuses.iter() @@ -128,7 +99,7 @@ pub async fn kill_generic_inference_jobs_handler( mysql_pool: &server_state.mysql_pool, }).await.map_err(|err| { warn!("Query Error: {:?}", err); - KillInferenceJobsError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = KillInferenceJobsResponse { @@ -136,7 +107,7 @@ pub async fn kill_generic_inference_jobs_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| KillInferenceJobsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/delete/terminate_inference_job_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/delete/terminate_inference_job_handler.rs index 634d414e0a..0e230ebca9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/delete/terminate_inference_job_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/delete/terminate_inference_job_handler.rs @@ -14,6 +14,7 @@ use mysql_queries::queries::generic_inference::web::mark_generic_inference_job_c use tokens::tokens::generic_inference_jobs::InferenceJobToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -26,41 +27,7 @@ pub struct TerminateInferenceJobPathInfo { pub struct TerminateInferenceJobSuccessResponse { pub success: bool, } - -#[derive(Debug, ToSchema)] -pub enum TerminateInferenceJobError { - ServerError, - NotFound, - NotAuthorized, -} - -impl ResponseError for TerminateInferenceJobError { - fn status_code(&self) -> StatusCode { - match *self { - TerminateInferenceJobError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - TerminateInferenceJobError::NotFound => StatusCode::NOT_FOUND, - TerminateInferenceJobError::NotAuthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - Self::ServerError => "server error".to_string(), - Self::NotFound => "not found".to_string(), - Self::NotAuthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for TerminateInferenceJobError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Terminate a job for the user. /// /// The user must own the job. This works for logged in users as well as logged out users @@ -74,19 +41,19 @@ impl fmt::Display for TerminateInferenceJobError { ), responses( (status = 200, body = TerminateInferenceJobSuccessResponse), - (status = 500, body = TerminateInferenceJobError), + (status = 500, body = CommonWebError), ), )] pub async fn terminate_inference_job_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { warn!("Could not acquire DB pool: {:?}", e); - TerminateInferenceJobError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -95,7 +62,7 @@ pub async fn terminate_inference_job_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - TerminateInferenceJobError::ServerError + CommonWebError::from_error(e) })?; let maybe_status = get_inference_job_status_from_connection( @@ -103,10 +70,10 @@ pub async fn terminate_inference_job_handler( let job_status = match maybe_status { Ok(Some(record)) => record, - Ok(None) => return Err(TerminateInferenceJobError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { error!("tts job query error: {:?}", err); - return Err(TerminateInferenceJobError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -117,13 +84,13 @@ pub async fn terminate_inference_job_handler( if let Some((session_user_token, job_user_token)) = maybe_user_tokens { if session_user_token != job_user_token { - return Err(TerminateInferenceJobError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } } else { let ip_address = get_request_ip(&http_request); if ip_address != job_status.user_details.creator_ip_address { // TODO(bt,2023-10-24): Allow if anonymous visitor token cookie matches - return Err(TerminateInferenceJobError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } } @@ -131,7 +98,7 @@ pub async fn terminate_inference_job_handler( .await .map_err(|err| { error!("tts job query error: {:?}", err); - TerminateInferenceJobError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = TerminateInferenceJobSuccessResponse { @@ -141,7 +108,7 @@ pub async fn terminate_inference_job_handler( let body = serde_json::to_string(&response) .map_err(|e| { error!("error returning response: {:?}", e); - TerminateInferenceJobError::ServerError + CommonWebError::from_error(e) })?; Ok(HttpResponse::Ok() diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_animation_type_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_animation_type_handler.rs index 2437aaef16..bcb13474fd 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_animation_type_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_animation_type_handler.rs @@ -15,6 +15,7 @@ use mysql_queries::queries::media_files::edit::update_media_file_animation_type: use mysql_queries::queries::media_files::get::get_media_file::get_media_file; use crate::http_server::common_requests::media_file_token_path_info::MediaFileTokenPathInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::simple_response::SimpleResponse; use crate::http_server::web_utils::user_session::require_user_session::require_user_session; use crate::state::server_state::ServerState; @@ -27,37 +28,7 @@ pub struct ChangeMediaFileAnimationTypeRequest { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum ChangeMediaFileAnimationTypeError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for ChangeMediaFileAnimationTypeError { - fn status_code(&self) -> StatusCode { - match *self { - ChangeMediaFileAnimationTypeError::BadInput(_) => StatusCode::BAD_REQUEST, - ChangeMediaFileAnimationTypeError::NotFound => StatusCode::NOT_FOUND, - ChangeMediaFileAnimationTypeError::NotAuthorized => StatusCode::UNAUTHORIZED, - ChangeMediaFileAnimationTypeError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ChangeMediaFileAnimationTypeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== /// Change the animation type for a media file. @@ -69,9 +40,9 @@ impl fmt::Display for ChangeMediaFileAnimationTypeError { path = "/v1/media_files/animation_type/{token}", responses( (status = 200, description = "Success", body = SimpleResponse), - (status = 400, description = "Bad input", body = ChangeMediaFileAnimationTypeError), - (status = 401, description = "Not authorized", body = ChangeMediaFileAnimationTypeError), - (status = 500, description = "Server error", body = ChangeMediaFileAnimationTypeError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = ChangeMediaFileAnimationTypeRequest, description = "Payload for Request"), @@ -83,13 +54,13 @@ pub async fn change_media_file_animation_type_handler( path: Path, request: Json, server_state: web::Data> -) -> Result, ChangeMediaFileAnimationTypeError> { +) -> Result, CommonWebError> { let user_session = require_user_session(&http_request, &server_state) .await .map_err(|e| { warn!("Not authorized: {:?}", e); - ChangeMediaFileAnimationTypeError::NotAuthorized + CommonWebError::NotAuthorized })?; let media_file_token = path.token.clone(); @@ -105,11 +76,11 @@ pub async fn change_media_file_animation_type_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("MediaFile not found: {:?}", media_file_token); - return Err(ChangeMediaFileAnimationTypeError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up media_file: {:?}", err); - return Err(ChangeMediaFileAnimationTypeError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -120,7 +91,7 @@ pub async fn change_media_file_animation_type_handler( Some(MediaFileEngineCategory::Character) => {} // Everything else is disallowed _ => { - return Err(ChangeMediaFileAnimationTypeError::BadInput( + return Err(CommonWebError::BadInputWithSimpleMessage( "this media file engine category does not support animation".to_string())); } } @@ -128,7 +99,7 @@ pub async fn change_media_file_animation_type_handler( if request.maybe_animation_type.is_none() && media_file.maybe_engine_category != Some(MediaFileEngineCategory::Character) { - return Err(ChangeMediaFileAnimationTypeError::BadInput( + return Err(CommonWebError::BadInputWithSimpleMessage( "animation type can only be cleared for character types".to_string())); } @@ -137,7 +108,7 @@ pub async fn change_media_file_animation_type_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this media_file: {:?}", user_session.user_token); - return Err(ChangeMediaFileAnimationTypeError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let query_result = update_media_file_animation_type( @@ -150,7 +121,7 @@ pub async fn change_media_file_animation_type_handler( Ok(_) => {}, Err(err) => { warn!("Update MediaFile DB error: {:?}", err); - return Err(ChangeMediaFileAnimationTypeError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_engine_category_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_engine_category_handler.rs index f5cb0d2809..16366191f9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_engine_category_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_engine_category_handler.rs @@ -14,6 +14,7 @@ use mysql_queries::queries::media_files::edit::update_media_file_engine_category use mysql_queries::queries::media_files::get::get_media_file::get_media_file; use crate::http_server::common_requests::media_file_token_path_info::MediaFileTokenPathInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::simple_response::SimpleResponse; use crate::http_server::web_utils::user_session::require_user_session::require_user_session; use crate::state::server_state::ServerState; @@ -24,37 +25,7 @@ pub struct ChangeMediaFileEngineCategoryRequest { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum ChangeMediaFileEngineCategoryError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for ChangeMediaFileEngineCategoryError { - fn status_code(&self) -> StatusCode { - match *self { - ChangeMediaFileEngineCategoryError::BadInput(_) => StatusCode::BAD_REQUEST, - ChangeMediaFileEngineCategoryError::NotFound => StatusCode::NOT_FOUND, - ChangeMediaFileEngineCategoryError::NotAuthorized => StatusCode::UNAUTHORIZED, - ChangeMediaFileEngineCategoryError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ChangeMediaFileEngineCategoryError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== /// Change the engine category of a media file. @@ -66,9 +37,9 @@ impl fmt::Display for ChangeMediaFileEngineCategoryError { path = "/v1/media_files/engine_category/{token}", responses( (status = 200, description = "Success", body = SimpleResponse), - (status = 400, description = "Bad input", body = ChangeMediaFileEngineCategoryError), - (status = 401, description = "Not authorized", body = ChangeMediaFileEngineCategoryError), - (status = 500, description = "Server error", body = ChangeMediaFileEngineCategoryError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = ChangeMediaFileEngineCategoryRequest, description = "Payload for Request"), @@ -80,13 +51,13 @@ pub async fn change_media_file_engine_category_handler( path: Path, request: Json, server_state: web::Data> -) -> Result, ChangeMediaFileEngineCategoryError> { +) -> Result, CommonWebError> { let user_session = require_user_session(&http_request, &server_state) .await .map_err(|e| { warn!("Not authorized: {:?}", e); - ChangeMediaFileEngineCategoryError::NotAuthorized + CommonWebError::NotAuthorized })?; let media_file_token = path.token.clone(); @@ -102,28 +73,28 @@ pub async fn change_media_file_engine_category_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("MediaFile not found: {:?}", media_file_token); - return Err(ChangeMediaFileEngineCategoryError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up media_file: {:?}", err); - return Err(ChangeMediaFileEngineCategoryError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; match media_file.maybe_engine_category { - None => return Err(ChangeMediaFileEngineCategoryError::BadInput( + None => return Err(CommonWebError::BadInputWithSimpleMessage( "No engine category on existing object".to_string())), Some(existing_category) => { if !is_valid_transition(existing_category) { - return Err(ChangeMediaFileEngineCategoryError::BadInput( + return Err(CommonWebError::BadInputWithSimpleMessage( format!("Invalid engine category on existing object: {:?}", existing_category))); } } } if !is_valid_transition(request.engine_category) { - return Err(ChangeMediaFileEngineCategoryError::BadInput( + return Err(CommonWebError::BadInputWithSimpleMessage( format!("Invalid engine category: {:?}", request.engine_category))); } @@ -132,7 +103,7 @@ pub async fn change_media_file_engine_category_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this media_file: {:?}", user_session.user_token); - return Err(ChangeMediaFileEngineCategoryError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let query_result = update_media_file_engine_category( @@ -145,7 +116,7 @@ pub async fn change_media_file_engine_category_handler( Ok(_) => {}, Err(err) => { warn!("Update MediaFile DB error: {:?}", err); - return Err(ChangeMediaFileEngineCategoryError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_visibility_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_visibility_handler.rs index 34c676c80c..1f9dfd3f92 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_visibility_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/change_media_file_visibility_handler.rs @@ -16,6 +16,7 @@ use mysql_queries::queries::media_files::edit::update_media_file_visibility::{up use mysql_queries::queries::media_files::get::get_media_file::get_media_file; use crate::http_server::common_requests::media_file_token_path_info::MediaFileTokenPathInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Deserialize, ToSchema)] @@ -24,37 +25,7 @@ pub struct ChangeMediaFileVisibilityRequest { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum ChangeMediaFileVisibilityError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for ChangeMediaFileVisibilityError { - fn status_code(&self) -> StatusCode { - match *self { - ChangeMediaFileVisibilityError::BadInput(_) => StatusCode::BAD_REQUEST, - ChangeMediaFileVisibilityError::NotFound => StatusCode::NOT_FOUND, - ChangeMediaFileVisibilityError::NotAuthorized => StatusCode::UNAUTHORIZED, - ChangeMediaFileVisibilityError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ChangeMediaFileVisibilityError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== /// Change the visibility (public, hidden, private) of a media file. @@ -64,9 +35,9 @@ impl fmt::Display for ChangeMediaFileVisibilityError { path = "/v1/media_files/visibility/{token}", responses( (status = 200, description = "Success", body = SimpleGenericJsonSuccess), - (status = 400, description = "Bad input", body = ChangeMediaFileVisibilityError), - (status = 401, description = "Not authorized", body = ChangeMediaFileVisibilityError), - (status = 500, description = "Server error", body = ChangeMediaFileVisibilityError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = ChangeMediaFileVisibilityRequest, description = "Payload for Request"), @@ -77,7 +48,7 @@ pub async fn change_media_file_visibility_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -85,14 +56,14 @@ pub async fn change_media_file_visibility_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ChangeMediaFileVisibilityError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ChangeMediaFileVisibilityError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -109,11 +80,11 @@ pub async fn change_media_file_visibility_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("MediaFile not found: {:?}", media_file_token); - return Err(ChangeMediaFileVisibilityError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up media_file: {:?}", err); - return Err(ChangeMediaFileVisibilityError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -122,7 +93,7 @@ pub async fn change_media_file_visibility_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this media_file: {:?}", user_session.user_token); - return Err(ChangeMediaFileVisibilityError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut creator_set_visibility = Visibility::Public; @@ -130,7 +101,7 @@ pub async fn change_media_file_visibility_handler( if let Some(visibility) = request.creator_set_visibility.as_deref() { creator_set_visibility = Visibility::from_str(visibility) - .map_err(|_| ChangeMediaFileVisibilityError::BadInput("bad record visibility".to_string()))?; + .map_err(|_| CommonWebError::BadInputWithSimpleMessage("bad record visibility".to_string()))?; } let ip_address = get_request_ip(&http_request); @@ -152,7 +123,7 @@ pub async fn change_media_file_visibility_handler( Ok(_) => {}, Err(err) => { warn!("Update MediaFile DB error: {:?}", err); - return Err(ChangeMediaFileVisibilityError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/rename_media_file_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/rename_media_file_handler.rs index 07bb5155ea..422d7eef62 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/rename_media_file_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/rename_media_file_handler.rs @@ -9,6 +9,7 @@ use log::warn; use utoipa::ToSchema; use crate::http_server::common_requests::media_file_token_path_info::MediaFileTokenPathInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; @@ -24,37 +25,7 @@ pub struct RenameMediaFileRequest { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum RenameMediaFileError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for RenameMediaFileError { - fn status_code(&self) -> StatusCode { - match *self { - RenameMediaFileError::BadInput(_) => StatusCode::BAD_REQUEST, - RenameMediaFileError::NotFound => StatusCode::NOT_FOUND, - RenameMediaFileError::NotAuthorized => StatusCode::UNAUTHORIZED, - RenameMediaFileError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for RenameMediaFileError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== /// Change (or remove) the "title" of a media file. @@ -64,9 +35,9 @@ impl fmt::Display for RenameMediaFileError { path = "/v1/media_files/rename/{token}", responses( (status = 200, description = "Success", body = SimpleGenericJsonSuccess), - (status = 400, description = "Bad input", body = RenameMediaFileError), - (status = 401, description = "Not authorized", body = RenameMediaFileError), - (status = 500, description = "Server error", body = RenameMediaFileError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = RenameMediaFileRequest, description = "Payload for Request"), @@ -78,21 +49,21 @@ pub async fn rename_media_file_handler( path: Path, request: web::Json, server_state: web::Data> -) -> Result{ +) -> Result{ let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - RenameMediaFileError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(RenameMediaFileError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -108,11 +79,11 @@ pub async fn rename_media_file_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("MediaFile not found: {:?}", path.token); - return Err(RenameMediaFileError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up media_file: {:?}", err); - return Err(RenameMediaFileError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -121,7 +92,7 @@ pub async fn rename_media_file_handler( if !is_creator && !is_mod { warn!("user is not allowed to delete this media_file: {:?}", user_session.user_token); - return Err(RenameMediaFileError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } rename_media_file( @@ -130,7 +101,7 @@ pub async fn rename_media_file_handler( &server_state.mysql_pool ).await.map_err(|err| { warn!("Error renaming media_file: {:?}", err); - RenameMediaFileError::ServerError + CommonWebError::from_anyhow_error(err) })?; Ok(simple_json_success()) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/set_media_file_cover_image_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/set_media_file_cover_image_handler.rs index 2e0b978b72..b2101d9196 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/set_media_file_cover_image_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/set_media_file_cover_image_handler.rs @@ -15,6 +15,7 @@ use mysql_queries::queries::media_files::get::get_media_file::get_media_file; use tokens::tokens::media_files::MediaFileToken; use crate::http_server::common_requests::media_file_token_path_info::MediaFileTokenPathInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; @@ -27,37 +28,7 @@ pub struct SetMediaFileCoverImageRequest { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum SetMediaFileCoverImageError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for SetMediaFileCoverImageError { - fn status_code(&self) -> StatusCode { - match *self { - SetMediaFileCoverImageError::BadInput(_) => StatusCode::BAD_REQUEST, - SetMediaFileCoverImageError::NotFound => StatusCode::NOT_FOUND, - SetMediaFileCoverImageError::NotAuthorized => StatusCode::UNAUTHORIZED, - SetMediaFileCoverImageError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for SetMediaFileCoverImageError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== /// Set or remove the "cover image" (which are used as thumbnails) on a file. @@ -70,9 +41,9 @@ impl fmt::Display for SetMediaFileCoverImageError { path = "/v1/media_files/cover_image/{token}", responses( (status = 200, description = "Success Delete", body = SimpleGenericJsonSuccess), - (status = 400, description = "Bad input", body = SetMediaFileCoverImageError), - (status = 401, description = "Not authorized", body = SetMediaFileCoverImageError), - (status = 500, description = "Server error", body = SetMediaFileCoverImageError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = SetMediaFileCoverImageRequest, description = "Payload for Request"), @@ -84,21 +55,21 @@ pub async fn set_media_file_cover_image_handler( path: Path, request: web::Json, server_state: web::Data> -) -> Result{ +) -> Result{ let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - SetMediaFileCoverImageError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(SetMediaFileCoverImageError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -114,11 +85,11 @@ pub async fn set_media_file_cover_image_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("MediaFile not found: {:?}", path.token); - return Err(SetMediaFileCoverImageError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up media_file: {:?}", err); - return Err(SetMediaFileCoverImageError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -127,7 +98,7 @@ pub async fn set_media_file_cover_image_handler( if !is_creator && !is_mod { warn!("user is not allowed to delete this media_file: {:?}", user_session.user_token); - return Err(SetMediaFileCoverImageError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut maybe_set_media_file_token = None; @@ -151,11 +122,11 @@ pub async fn set_media_file_cover_image_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("Media file not found: {:?}", media_file_token); - return Err(SetMediaFileCoverImageError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up model_weights : {:?}", err); - return Err(SetMediaFileCoverImageError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -165,7 +136,7 @@ pub async fn set_media_file_cover_image_handler( let can_use_image = media_file.media_type == MediaFileType::Image; if !can_use_image { - return Err(SetMediaFileCoverImageError::BadInput("Invalid media file token.".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("Invalid media file token.".to_string())); } maybe_set_media_file_token = Some(media_file.token); @@ -182,7 +153,7 @@ pub async fn set_media_file_cover_image_handler( Ok(_) => {}, Err(err) => { warn!("Update MediaFile DB error: {:?}", err); - return Err(SetMediaFileCoverImageError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/update_media_file_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/update_media_file_handler.rs index 60dfe4c163..affd7a55b2 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/update_media_file_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/edit/update_media_file_handler.rs @@ -16,6 +16,7 @@ use mysql_queries::queries::media_files::get::get_media_file::get_media_file; use tokens::tokens::media_files::MediaFileToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; #[derive(Deserialize)] pub struct UpdateMediaFileRequest { @@ -34,44 +35,14 @@ pub struct UpdateMediaFilePathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum UpdateMediaFileError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for UpdateMediaFileError { - fn status_code(&self) -> StatusCode { - match *self { - UpdateMediaFileError::BadInput(_) => StatusCode::BAD_REQUEST, - UpdateMediaFileError::NotFound => StatusCode::NOT_FOUND, - UpdateMediaFileError::NotAuthorized => StatusCode::UNAUTHORIZED, - UpdateMediaFileError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for UpdateMediaFileError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn update_media_file_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -79,14 +50,14 @@ pub async fn update_media_file_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - UpdateMediaFileError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(UpdateMediaFileError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -103,11 +74,11 @@ pub async fn update_media_file_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("MediaFile not found: {:?}", media_file_token); - return Err(UpdateMediaFileError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up media_file: {:?}", err); - return Err(UpdateMediaFileError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -116,7 +87,7 @@ pub async fn update_media_file_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this media_file: {:?}", user_session.user_token); - return Err(UpdateMediaFileError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut creator_set_visibility = Visibility::Public; @@ -124,7 +95,7 @@ pub async fn update_media_file_handler( if let Some(visibility) = request.creator_set_visibility.as_deref() { creator_set_visibility = Visibility::from_str(visibility) - .map_err(|_| UpdateMediaFileError::BadInput("bad record visibility".to_string()))?; + .map_err(|_| CommonWebError::BadInputWithSimpleMessage("bad record visibility".to_string()))?; } let ip_address = get_request_ip(&http_request); @@ -146,7 +117,7 @@ pub async fn update_media_file_handler( Ok(_) => {}, Err(err) => { warn!("Update MediaFile DB error: {:?}", err); - return Err(UpdateMediaFileError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_featured_media_files_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_featured_media_files_handler.rs index 421c28d5ff..5e8c74930d 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_featured_media_files_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_featured_media_files_handler.rs @@ -18,6 +18,7 @@ use tokens::tokens::media_files::MediaFileToken; use utoipa::{IntoParams, ToSchema}; use crate::http_server::common_responses::media::media_file_cover_image_details::MediaFileCoverImageDetails; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::media::media_links_builder::MediaLinksBuilder; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain; @@ -143,37 +144,6 @@ pub struct SearchFeaturedMediaFileListItem { pub created_at: DateTime, pub updated_at: DateTime, } - -#[derive(Debug, ToSchema)] -pub enum SearchFeaturedMediaFilesError { - ServerError, - NotAuthorized, -} - -impl ResponseError for SearchFeaturedMediaFilesError { - fn status_code(&self) -> StatusCode { - match *self { - SearchFeaturedMediaFilesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - SearchFeaturedMediaFilesError::NotAuthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - SearchFeaturedMediaFilesError::ServerError => "server error".to_string(), - SearchFeaturedMediaFilesError::NotAuthorized => "not authorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - -impl std::fmt::Display for SearchFeaturedMediaFilesError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - /// Search for featured media files based on various criteria. #[utoipa::path( get, @@ -182,14 +152,14 @@ impl std::fmt::Display for SearchFeaturedMediaFilesError { params(SearchFeaturedMediaFilesQueryParams), responses( (status = 200, description = "Success Response", body = SearchFeaturedMediaFilesSuccessResponse), - (status = 500, description = "Server error", body = SearchFeaturedMediaFilesError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn search_featured_media_files_handler( http_request: HttpRequest, query: Query, server_state: web::Data> -) -> Result, SearchFeaturedMediaFilesError> +) -> Result, CommonWebError> { let mut maybe_filter_media_types = get_scoped_media_types(query.filter_media_type.as_deref()); let mut maybe_filter_media_classes = get_scoped_media_classes(query.filter_media_classes.as_deref()); @@ -209,7 +179,7 @@ pub async fn search_featured_media_files_handler( Ok(results) => results, Err(err) => { warn!("Searching error: {:?}", err); - return Err(SearchFeaturedMediaFilesError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_session_media_files_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_session_media_files_handler.rs index da66f77d8b..dbfc757512 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_session_media_files_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/search/search_session_media_files_handler.rs @@ -19,6 +19,7 @@ use tokens::tokens::users::UserToken; use utoipa::{IntoParams, ToSchema}; use crate::http_server::common_responses::media::media_file_cover_image_details::MediaFileCoverImageDetails; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::media::media_links_builder::MediaLinksBuilder; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain; @@ -144,37 +145,6 @@ pub struct SearchMediaFileListItem { pub created_at: DateTime, pub updated_at: DateTime, } - -#[derive(Debug, ToSchema)] -pub enum SearchMediaFilesError { - ServerError, - NotAuthorized, -} - -impl ResponseError for SearchMediaFilesError { - fn status_code(&self) -> StatusCode { - match *self { - SearchMediaFilesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - SearchMediaFilesError::NotAuthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - SearchMediaFilesError::ServerError => "server error".to_string(), - SearchMediaFilesError::NotAuthorized => "not authorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - -impl std::fmt::Display for SearchMediaFilesError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - /// Search for media files for the active user based on various criteria. /// /// This only returns media files owned by the active user. @@ -185,15 +155,15 @@ impl std::fmt::Display for SearchMediaFilesError { params(SearchMediaFilesQueryParams), responses( (status = 200, description = "Success response", body = SearchMediaFilesSuccessResponse), - (status = 401, description = "Not authorized", body = SearchMediaFilesError), - (status = 500, description = "Server error", body = SearchMediaFilesError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn search_session_media_files_handler( http_request: HttpRequest, query: Query, server_state: web::Data> -) -> Result, SearchMediaFilesError> +) -> Result, CommonWebError> { // NB(bt,2024-07-01): This isn't great. Though we HMAC our cookies, this could // result in bad situations where we don't invalidate sessions, etc. We're only @@ -205,17 +175,17 @@ pub async fn search_session_media_files_handler( let session = match session_result { Ok(Some(session)) => session, Ok(None) => { - return Err(SearchMediaFilesError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); }, Err(err) => { warn!("Session decode error: {:?}", err); - return Err(SearchMediaFilesError::ServerError); + return Err(CommonWebError::from_error(err)); } }; let user_token = match session.maybe_user_token { Some(user_token) => UserToken::new_from_str(&user_token), - None => return Err(SearchMediaFilesError::NotAuthorized), + None => return Err(CommonWebError::NotAuthorized), }; let mut maybe_filter_media_types = get_scoped_media_types(query.filter_media_type.as_deref()); @@ -236,7 +206,7 @@ pub async fn search_session_media_files_handler( Ok(results) => results, Err(err) => { warn!("Searching error: {:?}", err); - return Err(SearchMediaFilesError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/misc/detect_locale_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/misc/detect_locale_handler.rs index e5ca515cb7..bdc597faf1 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/misc/detect_locale_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/misc/detect_locale_handler.rs @@ -7,6 +7,7 @@ use actix_web::web::Json; use actix_web::{web, HttpRequest, HttpResponse}; use crate::http_server::endpoints::app_state::components::get_user_locale::get_user_locale; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; @@ -22,37 +23,13 @@ pub struct DetectLocaleResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum DetectLocaleError { - ServerError, -} - -impl ResponseError for DetectLocaleError { - fn status_code(&self) -> StatusCode { - match *self { - DetectLocaleError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DetectLocaleError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn detect_locale_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result, DetectLocaleError> { +) -> Result, CommonWebError> { let locale = get_user_locale(&http_request); Ok(Json(DetectLocaleResponse { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/info/moderator_token_info_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/info/moderator_token_info_handler.rs index eef15a1728..130c76aaeb 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/info/moderator_token_info_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/info/moderator_token_info_handler.rs @@ -24,6 +24,7 @@ use tokens::tokens::prompts::PromptToken; use tokens::tokens::users::UserToken; use crate::http_server::web_utils::serialize_as_json_error::serialize_as_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_moderator::{require_moderator, RequireModeratorError, UseDatabase}; use crate::state::server_state::ServerState; @@ -39,41 +40,15 @@ pub struct ModeratorTokenInfoResponse { /// Json-encoded payload pub maybe_payload: Option, } - -#[derive(Debug, Serialize, ToSchema)] -pub enum ModeratorTokenInfoError { - ServerError, - Unauthorized, -} - -impl ResponseError for ModeratorTokenInfoError { - fn status_code(&self) -> StatusCode { - match *self { - ModeratorTokenInfoError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - ModeratorTokenInfoError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for ModeratorTokenInfoError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( get, tag = "Moderation", path = "/v1/moderation/token_info/{token}", responses( (status = 200, description = "Found", body = ModeratorTokenInfoResponse), - (status = 401, description = "Not authorized", body = ModeratorTokenInfoError), - (status = 500, description = "Server error", body = ModeratorTokenInfoError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("path" = ModeratorTokenInfoPath, description = "Path for Request") @@ -83,13 +58,13 @@ pub async fn moderator_get_token_info_handler( path: Path, http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let user_session = require_moderator(&http_request, &server_state, UseDatabase::GrabNewConnection) .await .map_err(|err| match err { - RequireModeratorError::ServerError => ModeratorTokenInfoError::ServerError, - RequireModeratorError::NotAuthorized => ModeratorTokenInfoError::Unauthorized, + RequireModeratorError::ServerError => CommonWebError::from_error(err), + RequireModeratorError::NotAuthorized => CommonWebError::NotAuthorized, })?; let token = path.token.trim(); @@ -97,7 +72,7 @@ pub async fn moderator_get_token_info_handler( .await .map_err(|err| { warn!("get tts pending count error: {:?}", err); - ModeratorTokenInfoError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = ModeratorTokenInfoResponse { @@ -106,7 +81,7 @@ pub async fn moderator_get_token_info_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ModeratorTokenInfoError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/add_ip_ban.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/add_ip_ban.rs index 8dcd3a8d5e..aaf371dce9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/add_ip_ban.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/add_ip_ban.rs @@ -10,6 +10,7 @@ use mysql_queries::queries::ip_bans::upsert_ip_ban::{upsert_ip_ban, UpsertIpBanA use user_input_common::validate_user_provided_ip_address::validate_user_provided_ip_address; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; @@ -19,46 +20,12 @@ pub struct AddIpBanRequest { mod_notes: String, maybe_target_user_token: Option, } - -#[derive(Debug)] -pub enum AddIpBanError { - BadInput(String), - ServerError, - Unauthorized, -} - -impl ResponseError for AddIpBanError { - fn status_code(&self) -> StatusCode { - match *self { - AddIpBanError::BadInput(_) => StatusCode::BAD_REQUEST, - AddIpBanError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - AddIpBanError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - AddIpBanError::BadInput(reason) => reason.to_string(), - AddIpBanError::ServerError => "server error".to_string(), - AddIpBanError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for AddIpBanError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn add_ip_ban_handler( http_request: HttpRequest, request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -66,27 +33,27 @@ pub async fn add_ip_ban_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - AddIpBanError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(AddIpBanError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; if !user_session.can_ban_users { warn!("user is not allowed to add bans: {:?}", user_session.user_token); - return Err(AddIpBanError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let ip_address = request.ip_address.trim(); if let Err(e) = validate_user_provided_ip_address(&ip_address) { warn!("Bad ip address: {}", e); - return Err(AddIpBanError::BadInput(e.to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage(e.to_string())); } info!("Creating ban..."); @@ -100,7 +67,7 @@ pub async fn add_ip_ban_handler( }).await .map_err(|err| { warn!("Add IP ban DB error: {:?}", err); - AddIpBanError::ServerError + CommonWebError::from_anyhow_error(err) })?; Ok(simple_json_success()) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/delete_ip_ban.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/delete_ip_ban.rs index eb938cb95a..5cbe146b6a 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/delete_ip_ban.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/delete_ip_ban.rs @@ -10,6 +10,7 @@ use log::{info, warn}; use mysql_queries::queries::ip_bans::toggle_ip_ban::{toggle_ip_ban, IpBanToggleState}; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; @@ -23,40 +24,12 @@ pub struct DeleteIpBanPathInfo { pub struct DeleteIpBanRequest { delete: bool, } - -#[derive(Debug, Display)] -pub enum DeleteIpBanError { - BadInput(String), - ServerError, - Unauthorized, -} - -impl ResponseError for DeleteIpBanError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteIpBanError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteIpBanError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - DeleteIpBanError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - DeleteIpBanError::BadInput(reason) => reason.to_string(), - DeleteIpBanError::ServerError => "server error".to_string(), - DeleteIpBanError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - pub async fn delete_ip_ban_handler( http_request: HttpRequest, path: Path, request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -64,20 +37,20 @@ pub async fn delete_ip_ban_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteIpBanError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteIpBanError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; if !user_session.can_ban_users { warn!("user is not allowed to delete bans: {:?}", user_session.user_token.as_str()); - return Err(DeleteIpBanError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let toggle_action = if request.delete { @@ -100,7 +73,7 @@ pub async fn delete_ip_ban_handler( Ok(_) => {}, Err(err) => { warn!("(un)delete IP ban DB error: {:?}", err); - return Err(DeleteIpBanError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/get_ip_ban.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/get_ip_ban.rs index bc3e1c4d53..260edd35b3 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/get_ip_ban.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/get_ip_ban.rs @@ -11,6 +11,7 @@ use log::{error, warn}; use mysql_queries::queries::ip_bans::get_ip_ban::get_ip_ban; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -37,42 +38,11 @@ pub struct IpBanRecord { pub created_at: DateTime, pub updated_at: DateTime, } - -#[derive(Debug, Display)] -pub enum GetIpBanError { - BadInput(String), - ServerError, - NotFound, - Unauthorized, -} - -impl ResponseError for GetIpBanError { - fn status_code(&self) -> StatusCode { - match *self { - GetIpBanError::BadInput(_) => StatusCode::BAD_REQUEST, - GetIpBanError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetIpBanError::NotFound => StatusCode::NOT_FOUND, - GetIpBanError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetIpBanError::BadInput(reason) => reason.to_string(), - GetIpBanError::ServerError => "server error".to_string(), - GetIpBanError::NotFound => "not found".to_string(), - GetIpBanError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - pub async fn get_ip_ban_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -80,20 +50,20 @@ pub async fn get_ip_ban_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetIpBanError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(GetIpBanError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; if !user_session.can_ban_users { warn!("user is not allowed to view bans: {:?}", user_session.user_token); - return Err(GetIpBanError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let ip_address = path.ip_address.trim(); @@ -102,12 +72,12 @@ pub async fn get_ip_ban_handler( .await .map_err(|err| { error!("get ip ban db error: {:?}", err); - GetIpBanError::ServerError + CommonWebError::from_anyhow_error(err) })?; let result : IpBanRecord = match maybe_result { None => { - return Err(GetIpBanError::NotFound); + return Err(CommonWebError::NotFound); }, Some(ban) => IpBanRecord { ip_address: ban.ip_address, @@ -128,7 +98,7 @@ pub async fn get_ip_ban_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetIpBanError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/list_ip_bans.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/list_ip_bans.rs index a9ccdde7a7..29fa9bccf6 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/list_ip_bans.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/ip_bans/list_ip_bans.rs @@ -9,6 +9,7 @@ use log::{error, warn}; use mysql_queries::queries::ip_bans::list_ip_bans::list_ip_bans; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -29,45 +30,11 @@ pub struct IpBanRecordForList { pub created_at: DateTime, pub updated_at: DateTime, } - -#[derive(Debug)] -pub enum ListIpBansError { - BadInput(String), - ServerError, - Unauthorized, -} - -impl ResponseError for ListIpBansError { - fn status_code(&self) -> StatusCode { - match *self { - ListIpBansError::BadInput(_) => StatusCode::BAD_REQUEST, - ListIpBansError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - ListIpBansError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListIpBansError::BadInput(reason) => reason.to_string(), - ListIpBansError::ServerError => "server error".to_string(), - ListIpBansError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl std::fmt::Display for ListIpBansError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_ip_bans_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -75,27 +42,27 @@ pub async fn list_ip_bans_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListIpBansError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ListIpBansError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; if !user_session.can_ban_users { warn!("user is not allowed to see bans: {:?}", user_session.user_token); - return Err(ListIpBansError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let results = list_ip_bans(&server_state.mysql_pool) .await .map_err(|err| { error!("list ip bans db error: {:?}", err); - ListIpBansError::ServerError + CommonWebError::from_anyhow_error(err) })? .into_iter() .map(|ban| { @@ -119,7 +86,7 @@ pub async fn list_ip_bans_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListIpBansError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/get_tts_inference_queue_count.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/get_tts_inference_queue_count.rs index c7e3fe69bc..753082dc5c 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/get_tts_inference_queue_count.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/get_tts_inference_queue_count.rs @@ -9,6 +9,7 @@ use log::warn; use mysql_queries::queries::tts::tts_inference_jobs::get_pending_tts_inference_job_detailed_stats::{get_pending_tts_inference_job_detailed_stats, PendingCountResult}; use crate::http_server::web_utils::serialize_as_json_error::serialize_as_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -29,37 +30,11 @@ pub struct GetTtsInferenceQueueCountResponse { // Failed, but not permanently dead pub attempt_failed_count: i64, } - -#[derive(Debug, Serialize)] -pub enum GetTtsInferenceQueueCountError { - ServerError, - Unauthorized, -} - -impl ResponseError for GetTtsInferenceQueueCountError { - fn status_code(&self) -> StatusCode { - match *self { - GetTtsInferenceQueueCountError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetTtsInferenceQueueCountError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for GetTtsInferenceQueueCountError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_tts_inference_queue_count_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -67,28 +42,28 @@ pub async fn get_tts_inference_queue_count_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetTtsInferenceQueueCountError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(GetTtsInferenceQueueCountError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: Not a good fit for this permission. if !user_session.can_ban_users { warn!("user is not allowed to view bans: {:?}", user_session.user_token); - return Err(GetTtsInferenceQueueCountError::Unauthorized); + return Err(CommonWebError::NotAuthorized); } let result = get_pending_tts_inference_job_detailed_stats(&server_state.mysql_pool) .await .map_err(|err| { warn!("get tts pending count error: {:?}", err); - GetTtsInferenceQueueCountError::ServerError + CommonWebError::from_anyhow_error(err) })? .unwrap_or( // NB: Not Found for null results means nothing is pending in the queue (not an error!) @@ -111,7 +86,7 @@ pub async fn get_tts_inference_queue_count_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetTtsInferenceQueueCountError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/kill_tts_inference_jobs.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/kill_tts_inference_jobs.rs index f7751e690b..bca96c4f9c 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/kill_tts_inference_jobs.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/jobs/kill_tts_inference_jobs.rs @@ -10,6 +10,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::tts::tts_inference_jobs::kill_tts_inference_jobs::{kill_tts_inference_jobs, JobStatus}; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -39,43 +40,13 @@ pub struct KillTtsInferenceJobsResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum KillTtsInferenceJobsError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for KillTtsInferenceJobsError { - fn status_code(&self) -> StatusCode { - match *self { - KillTtsInferenceJobsError::BadInput(_) => StatusCode::BAD_REQUEST, - KillTtsInferenceJobsError::NotFound => StatusCode::NOT_FOUND, - KillTtsInferenceJobsError::NotAuthorized => StatusCode::UNAUTHORIZED, - KillTtsInferenceJobsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for KillTtsInferenceJobsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn kill_tts_inference_jobs_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -83,21 +54,21 @@ pub async fn kill_tts_inference_jobs_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - KillTtsInferenceJobsError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(KillTtsInferenceJobsError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; // TODO: We don't have a permission for this, so use this as a proxy permission if !user_session.can_ban_users { warn!("no permission to edit categories"); - return Err(KillTtsInferenceJobsError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let job_status = match request.kill_action { @@ -110,7 +81,7 @@ pub async fn kill_tts_inference_jobs_handler( .await .map_err(|e| { error!("Error with query: {:?}", e); - KillTtsInferenceJobsError::ServerError + CommonWebError::from_anyhow_error(e) })?; let response = KillTtsInferenceJobsResponse { @@ -118,7 +89,7 @@ pub async fn kill_tts_inference_jobs_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| KillTtsInferenceJobsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/user_feature_flags/moderator_edit_user_feature_flags_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/user_feature_flags/moderator_edit_user_feature_flags_handler.rs index 3b6846b08b..d208ecca2e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/user_feature_flags/moderator_edit_user_feature_flags_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/moderation/user_feature_flags/moderator_edit_user_feature_flags_handler.rs @@ -24,6 +24,7 @@ use mysql_queries::queries::users::user_profiles::get_user_profile_by_token::get use tokens::tokens::users::UserToken; use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::http_server::web_utils::user_session::require_moderator::{ @@ -64,50 +65,16 @@ pub enum EditUserFeatureFlagsOption { /// Clear all flags from the user. ClearAllFlags, } - -#[derive(Debug, ToSchema)] -pub enum EditUserFeatureFlagsError { - BadInput(String), - ServerError, - Unauthorized, -} - -impl ResponseError for EditUserFeatureFlagsError { - fn status_code(&self) -> StatusCode { - match *self { - EditUserFeatureFlagsError::BadInput(_) => StatusCode::BAD_REQUEST, - EditUserFeatureFlagsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - EditUserFeatureFlagsError::Unauthorized => StatusCode::UNAUTHORIZED, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - EditUserFeatureFlagsError::BadInput(reason) => reason.to_string(), - EditUserFeatureFlagsError::ServerError => "server error".to_string(), - EditUserFeatureFlagsError::Unauthorized => "unauthorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditUserFeatureFlagsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( post, tag = "Moderation", path = "/v1/moderation/user_feature_flags/user/{username_or_token}", responses( (status = 200, description = "Success", body = SimpleGenericJsonSuccess), - (status = 401, description = "Unauthorized", body = EditUserFeatureFlagsError), - (status = 404, description = "Not found", body = EditUserFeatureFlagsError), - (status = 500, description = "Server error", body = EditUserFeatureFlagsError), + (status = 401, description = "Unauthorized", body = CommonWebError), + (status = 404, description = "Not found", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("path" = EditUserFeatureFlagPathInfo, description = "Path for Request"), @@ -120,7 +87,7 @@ pub async fn moderator_edit_user_feature_flags_handler( request: Json, server_state: Data>, redis_pool: Data>, -) -> Result { +) -> Result { let user_session = require_moderator( &http_request, @@ -128,7 +95,7 @@ pub async fn moderator_edit_user_feature_flags_handler( UseDatabase::GrabNewConnection, ).await.map_err(|err| { warn!("Moderator check failed: {:?}", err); - EditUserFeatureFlagsError::Unauthorized + CommonWebError::NotAuthorized })?; let username_or_token = path.username_or_token.trim(); @@ -140,18 +107,18 @@ pub async fn moderator_edit_user_feature_flags_handler( .await .map_err(|e| { warn!("Could not get user token by username: {:?}", e); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_anyhow_error(e) })? - .ok_or(EditUserFeatureFlagsError::ServerError)? + .ok_or(CommonWebError::server_error_with_message("uncaught server error"))? }; let user_profile = get_user_profile_by_token(&user_token, &server_state.mysql_pool) .await .map_err(|e| { warn!("Could not get user profile by token: {:?}", e); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_anyhow_error(e) })? - .ok_or(EditUserFeatureFlagsError::ServerError)?; + .ok_or(CommonWebError::server_error_with_message("uncaught server error"))?; let mut user_feature_flags = UserSessionFeatureFlags::new(user_profile.maybe_feature_flags.as_deref()); @@ -188,7 +155,7 @@ pub async fn moderator_edit_user_feature_flags_handler( }).await .map_err(|e| { warn!("Could not set flags: {:?}", e); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_anyhow_error(e) })?; // Insert staff audit log. @@ -196,14 +163,14 @@ pub async fn moderator_edit_user_feature_flags_handler( .await .map_err(|e| { warn!("Could not acquire MySQL connection for audit log: {:?}", e); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_error(e) })?; let mut transaction = mysql_connection.begin() .await .map_err(|e| { warn!("Could not start transaction for audit log: {:?}", e); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_error(e) })?; let _audit_token = insert_staff_audit_log(InsertStaffAuditLogArgs { @@ -216,14 +183,14 @@ pub async fn moderator_edit_user_feature_flags_handler( phantom: PhantomData, }).await.map_err(|err| { warn!("Failed to insert staff audit log: {:?}", err); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_error(err) })?; transaction.commit() .await .map_err(|e| { warn!("Could not commit audit log transaction: {:?}", e); - EditUserFeatureFlagsError::ServerError + CommonWebError::from_error(e) })?; // Invalidate Redis cache for the user profile. diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/service/public_info_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/service/public_info_handler.rs index 4c1ccf2cc8..392ce054b5 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/service/public_info_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/service/public_info_handler.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use crate::http_server::endpoints::app_state::components::get_server_info::get_server_info; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use actix_web::http::StatusCode; use actix_web::web::Json; @@ -13,35 +14,11 @@ pub struct PublicInfoResponse { pub server_build_sha: String, pub server_hostname: String, } - -#[derive(Debug, Serialize)] -pub enum PublicInfoError { - ServerError, -} - -impl ResponseError for PublicInfoError { - fn status_code(&self) -> StatusCode { - match *self { - PublicInfoError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl std::fmt::Display for PublicInfoError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_public_info_handler( _http_request: HttpRequest, server_state: web::Data> -) -> Result, PublicInfoError> { +) -> Result, CommonWebError> { let server_info = get_server_info(&server_state); Ok(Json(PublicInfoResponse { success: true, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/service/status_alert_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/service/status_alert_handler.rs index f57b8a7362..49f25c9315 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/service/status_alert_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/service/status_alert_handler.rs @@ -7,6 +7,7 @@ use actix_web::{web, HttpRequest, HttpResponse, ResponseError}; use utoipa::ToSchema; use crate::http_server::endpoints::app_state::components::get_status_alert::{get_status_alert, AppStateStatusAlertCategory}; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; @@ -51,31 +52,7 @@ pub enum StatusAlertCategory { /// System is down for maintenance DownForMaintenance, } - -#[derive(Debug, Serialize, ToSchema)] -pub enum StatusAlertError { - ServerError, -} - -impl ResponseError for StatusAlertError { - fn status_code(&self) -> StatusCode { - match *self { - StatusAlertError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl std::fmt::Display for StatusAlertError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( get, tag = "Misc", @@ -86,13 +63,13 @@ impl std::fmt::Display for StatusAlertError { description = "Check service status for frontend alert messages", body = StatusAlertResponse, ), - (status = 500, description = "Server error", body = StatusAlertError) + (status = 500, description = "Server error", body = CommonWebError) ), )] pub async fn status_alert_handler( _http_request: HttpRequest, server_state: web::Data> -) -> Result, StatusAlertError> { +) -> Result, CommonWebError> { let maybe_alert = get_status_alert(&server_state); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/subscriptions/unsubscribe_reason.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/subscriptions/unsubscribe_reason.rs index 79c4a7333f..91649d02bd 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/subscriptions/unsubscribe_reason.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/subscriptions/unsubscribe_reason.rs @@ -9,6 +9,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::unsubscribe_reason::insert_unsubscribe_reason::UnsubscribeReasonInsertBuilder; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -26,44 +27,18 @@ pub struct SetUnsubscribeReasonResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum SetUnsubscribeReasonError { - NotAuthorized, - ServerError, -} - -impl ResponseError for SetUnsubscribeReasonError { - fn status_code(&self) -> StatusCode { - match *self { - SetUnsubscribeReasonError::NotAuthorized => StatusCode::UNAUTHORIZED, - SetUnsubscribeReasonError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - -impl std::fmt::Display for SetUnsubscribeReasonError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn set_unsubscribe_reason_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { error!("Could not acquire DB pool: {:?}", e); - SetUnsubscribeReasonError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -72,14 +47,14 @@ pub async fn set_unsubscribe_reason_handler( .await .map_err(|e| { error!("Session checker error: {:?}", e); - SetUnsubscribeReasonError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { info!("not logged in"); - return Err(SetUnsubscribeReasonError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -91,7 +66,7 @@ pub async fn set_unsubscribe_reason_handler( .set_unsubscribe_reason(&request.reason) .insert(&mut mysql_connection) .await - .map_err(|_e| SetUnsubscribeReasonError::ServerError)?; + .map_err(CommonWebError::from_anyhow_error)?; let response = SetUnsubscribeReasonResponse { @@ -99,7 +74,7 @@ pub async fn set_unsubscribe_reason_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| SetUnsubscribeReasonError::ServerError)?; + .map_err(|_e| CommonWebError::from_error(_e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tags/list_tags_for_entity_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tags/list_tags_for_entity_handler.rs index 4aaa3c4918..1ce5476cd8 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tags/list_tags_for_entity_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tags/list_tags_for_entity_handler.rs @@ -7,6 +7,7 @@ use std::fmt; use std::sync::Arc; use crate::http_server::common_responses::tag_info::TagInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::state::server_state::ServerState; use actix_web::error::ResponseError; @@ -34,41 +35,7 @@ pub struct ListTagsForEntitySuccessResponse { pub success: bool, pub tags: Vec, } - -#[derive(Debug, ToSchema)] -pub enum ListTagsForEntityError { - NotFound, - ServerError, - BadInput(String), -} - -impl ResponseError for ListTagsForEntityError { - fn status_code(&self) -> StatusCode { - match *self { - ListTagsForEntityError::NotFound => StatusCode::NOT_FOUND, - ListTagsForEntityError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - ListTagsForEntityError::BadInput(_) => StatusCode::BAD_REQUEST, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListTagsForEntityError::NotFound => "not found".to_string(), - ListTagsForEntityError::ServerError => "server error".to_string(), - ListTagsForEntityError::BadInput(ref reason) => reason.clone(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTagsForEntityError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// List the tags for an entity #[utoipa::path( get, @@ -76,9 +43,9 @@ impl fmt::Display for ListTagsForEntityError { path = "/v1/tags/list/{entity_type}/{entity_token}", responses( (status = 200, description = "Success", body = ListTagsForEntitySuccessResponse), - (status = 400, description = "Bad input", body = ListTagsForEntityError), - (status = 401, description = "Not authorized", body = ListTagsForEntityError), - (status = 500, description = "Server error", body = ListTagsForEntityError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = ListTagsForEntityPathInfo, description = "Payload for Request"), @@ -88,7 +55,7 @@ pub async fn list_tags_for_entity_handler( http_request: HttpRequest, path: Path, server_state: web::Data>, -) -> Result, ListTagsForEntityError> +) -> Result, CommonWebError> { let token = path.entity_token.as_str(); let token_prefix_matches = match path.entity_type { @@ -98,7 +65,7 @@ pub async fn list_tags_for_entity_handler( if !token_prefix_matches { warn!("invalid token prefix: {:?} for {:?}", path.entity_token, path.entity_type); - return Err(ListTagsForEntityError::BadInput("invalid token prefix".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid token prefix".to_string())); } let mut mysql_connection = server_state.mysql_pool @@ -106,7 +73,7 @@ pub async fn list_tags_for_entity_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - ListTagsForEntityError::ServerError + CommonWebError::from_error(err) })?; let entity = TagUseEntity::from_entity_type_and_token( @@ -116,7 +83,7 @@ pub async fn list_tags_for_entity_handler( .await .map_err(|e| { warn!("error listing tags: {:?}", e); - ListTagsForEntityError::ServerError + CommonWebError::from_anyhow_error(e) })?; tags.sort_by(|a, b| a.tag_value.cmp(&b.tag_value)); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tags/set_tags_for_entity_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tags/set_tags_for_entity_handler.rs index c3a678f8e7..65f16ebcf4 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tags/set_tags_for_entity_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tags/set_tags_for_entity_handler.rs @@ -7,6 +7,7 @@ use std::fmt; use std::sync::Arc; use crate::http_server::common_responses::tag_info::TagInfo; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::http_server::web_utils::user_session::require_user_session_extended_using_connection::require_user_session_extended_using_connection; use crate::state::server_state::ServerState; @@ -51,44 +52,7 @@ pub struct SetTagsForEntitySuccessResponse { pub success: bool, pub tags: Vec, } - -#[derive(Debug, ToSchema)] -pub enum SetTagsForEntityError { - BadInput(String), - NotAuthorized, - NotFound, - ServerError, -} - -impl ResponseError for SetTagsForEntityError { - fn status_code(&self) -> StatusCode { - match *self { - SetTagsForEntityError::BadInput(_) => StatusCode::BAD_REQUEST, - SetTagsForEntityError::NotAuthorized => StatusCode::UNAUTHORIZED, - SetTagsForEntityError::NotFound => StatusCode::NOT_FOUND, - SetTagsForEntityError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - SetTagsForEntityError::BadInput(reason) => reason.to_string(), - SetTagsForEntityError::NotAuthorized => "unauthorized".to_string(), - SetTagsForEntityError::NotFound => "not found".to_string(), - SetTagsForEntityError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for SetTagsForEntityError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Edit the tags (in bulk) for an entity. Comma-separated. #[utoipa::path( post, @@ -96,9 +60,9 @@ impl fmt::Display for SetTagsForEntityError { path = "/v1/tags/edit/{entity_type}/{entity_token}", responses( (status = 200, description = "Success", body = SetTagsForEntitySuccessResponse), - (status = 400, description = "Bad input", body = SetTagsForEntityError), - (status = 401, description = "Not authorized", body = SetTagsForEntityError), - (status = 500, description = "Server error", body = SetTagsForEntityError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = SetTagsForEntityRequest, description = "Payload for Request"), @@ -109,7 +73,7 @@ pub async fn set_tags_for_entity_handler( request: Json, path: Path, server_state: Data>, -) -> Result, SetTagsForEntityError> +) -> Result, CommonWebError> { let token = path.entity_token.as_str(); let token_prefix_matches = match path.entity_type { @@ -119,7 +83,7 @@ pub async fn set_tags_for_entity_handler( if !token_prefix_matches { warn!("invalid token prefix: {:?} for {:?}", path.entity_token, path.entity_type); - return Err(SetTagsForEntityError::BadInput("invalid token prefix".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid token prefix".to_string())); } let mut mysql_connection = server_state.mysql_pool @@ -127,7 +91,7 @@ pub async fn set_tags_for_entity_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - SetTagsForEntityError::ServerError + CommonWebError::from_error(err) })?; let user_session = require_user_session_extended_using_connection( @@ -136,11 +100,11 @@ pub async fn set_tags_for_entity_handler( &mut mysql_connection) .await .map_err(|_err| { - SetTagsForEntityError::NotAuthorized + CommonWebError::NotAuthorized })?; if user_session.role.is_banned { - return Err(SetTagsForEntityError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let is_mod = user_session.role.can_ban_users; @@ -154,7 +118,7 @@ pub async fn set_tags_for_entity_handler( if !is_creator && !is_mod { warn!("user is not allowed to modify entity: {:?}", user_session.user_token); - return Err(SetTagsForEntityError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let request_tags = to_normalized_tags(&request.tags); @@ -169,7 +133,7 @@ pub async fn set_tags_for_entity_handler( .collect::>()) .map_err(|e| { warn!("error selecting tags: {:?}", e); - SetTagsForEntityError::ServerError + CommonWebError::from_anyhow_error(e) })?; let matching_tag_values = matching_tags @@ -191,7 +155,7 @@ pub async fn set_tags_for_entity_handler( .await .map_err(|e| { warn!("error creating tag: {:?}", e); - SetTagsForEntityError::ServerError + CommonWebError::from_error(e) })?; new_tags.push(TagInfo { token, @@ -217,7 +181,7 @@ pub async fn set_tags_for_entity_handler( .await .map_err(|e| { warn!("error updating tags: {:?}", e); - SetTagsForEntityError::ServerError + CommonWebError::from_anyhow_error(e) })?; Ok(Json(SetTagsForEntitySuccessResponse { @@ -231,7 +195,7 @@ async fn get_is_creator( entity_token: &str, user_token: &UserToken, mysql_connection: &mut MySqlConnection -) -> Result { +) -> Result { match entity_type { TagUseEntityType::MediaFile => { let entity_token = MediaFileToken::new_from_str(entity_token); @@ -245,10 +209,10 @@ async fn get_is_creator( Ok(media_file.maybe_creator_user_token .is_some_and(|t| t.as_str() == user_token.as_str())) }, - Ok(None) => Err(SetTagsForEntityError::NotFound), + Ok(None) => Err(CommonWebError::NotFound), Err(err) => { warn!("Error looking up media_file: {:?}", err); - Err(SetTagsForEntityError::ServerError) + Err(CommonWebError::from_anyhow_error(err)) } } } @@ -263,10 +227,10 @@ async fn get_is_creator( Ok(Some(model_weight)) => { Ok(model_weight.creator_user_token.as_str() == user_token.as_str()) }, - Ok(None) => Err(SetTagsForEntityError::NotFound), + Ok(None) => Err(CommonWebError::NotFound), Err(err) => { warn!("Error looking up model_weight: {:?}", err); - Err(SetTagsForEntityError::ServerError) + Err(CommonWebError::from_anyhow_error(err)) } } } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/trending/list_trending_tts_models.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/trending/list_trending_tts_models.rs index a5fbcbbede..c96031fc9f 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/trending/list_trending_tts_models.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/trending/list_trending_tts_models.rs @@ -22,6 +22,7 @@ use mysql_queries::queries::trending_model_analytics::list_trending_tts_models:: use tokens::tokens::tts_models::TtsModelToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // TODO TODO TODO: This endpoint is not done! // TODO TODO TODO: This endpoint is not done! @@ -45,36 +46,12 @@ pub type WindowTrends = HashMap>; // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum ListTrendingTtsModelsError { - ServerError, -} - -impl ResponseError for ListTrendingTtsModelsError { - fn status_code(&self) -> StatusCode { - match *self { - ListTrendingTtsModelsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTrendingTtsModelsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn list_trending_tts_models_handler( _http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { // TODO: Cache the outputs! @@ -82,7 +59,7 @@ pub async fn list_trending_tts_models_handler( // let maybe_category_assignments = server_state.caches.tts_model_category_assignments.copy_without_bump_if_unexpired() // .map_err(|e| { // error!("Error consulting cache: {:?}", e); -// ListTrendingTtsModelsError::ServerError +// CommonWebError::from_error(e) // })?; // // let category_assignments = match maybe_category_assignments { @@ -99,7 +76,7 @@ pub async fn list_trending_tts_models_handler( // server_state.caches.tts_model_category_assignments.store_copy(&category_assignments) // .map_err(|e| { // error!("Error storing cache: {:?}", e); -// ListTrendingTtsModelsError::ServerError +// CommonWebError::from_error(e) // })?; // // category_assignments @@ -109,7 +86,7 @@ pub async fn list_trending_tts_models_handler( let trending_models= list_trending_tts_models_with_pool(&server_state.mysql_pool).await .map_err(|e| { error!("Query error: {:?}", e); - ListTrendingTtsModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; // TODO: Actually generate the response body sensibly. @@ -136,7 +113,7 @@ pub async fn list_trending_tts_models_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ListTrendingTtsModelsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_model.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_model.rs index f62c464173..45a594e4b3 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_model.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_model.rs @@ -15,6 +15,7 @@ use mysql_queries::queries::tts::tts_models::delete_tts_model_various_scopes::un use mysql_queries::queries::tts::tts_models::get_tts_model::get_tts_model_by_token; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; use crate::util::delete_role_disambiguation::delete_role_disambiguation; @@ -32,54 +33,17 @@ pub struct DeleteTtsModelRequest { /// NB: this is only to disambiguate when a user is both a mod and an author. as_mod: Option, } - -#[derive(Debug)] -pub enum DeleteTtsModelError { - BadInput(String), - NotAuthorized, - NotFound, - ServerError, -} - -impl ResponseError for DeleteTtsModelError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteTtsModelError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteTtsModelError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteTtsModelError::NotFound => StatusCode::NOT_FOUND, - DeleteTtsModelError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - DeleteTtsModelError::BadInput(reason) => reason.to_string(), - DeleteTtsModelError::NotAuthorized => "unauthorized".to_string(), - DeleteTtsModelError::NotFound => "not found".to_string(), - DeleteTtsModelError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteTtsModelError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn delete_tts_model_handler( http_request: HttpRequest, path: Path, request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { // NB: Disable if we've migrated to model_weights if server_state.flags.switch_tts_to_model_weights { warn!("Migration to model_weights for tts. Cannot delete old model."); - return Err(DeleteTtsModelError::ServerError); + return Err(CommonWebError::server_error_with_message("uncaught server error")); } let maybe_user_session = server_state @@ -88,14 +52,14 @@ pub async fn delete_tts_model_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteTtsModelError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteTtsModelError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -112,9 +76,9 @@ pub async fn delete_tts_model_handler( let tts_model = match model_query_result { Err(e) => { warn!("query error: {:?}", e); - return Err(DeleteTtsModelError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } - Ok(None) => return Err(DeleteTtsModelError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Ok(Some(model)) => model, }; @@ -123,13 +87,13 @@ pub async fn delete_tts_model_handler( if !is_author && !is_mod { warn!("user is not allowed to delete models: {:?}", user_session.user_token); - return Err(DeleteTtsModelError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } if !is_mod { if tts_model.is_locked_from_user_modification || tts_model.is_locked_from_use { warn!("user is not allowed to delete models (locked): {:?}", user_session.user_token); - return Err(DeleteTtsModelError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } } @@ -141,7 +105,7 @@ pub async fn delete_tts_model_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to delete model: {:?}", user_session.user_token); - return Err(DeleteTtsModelError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { delete_tts_model_as_user( @@ -162,7 +126,7 @@ pub async fn delete_tts_model_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to undelete model: {:?}", user_session.user_token); - return Err(DeleteTtsModelError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { // NB: Technically only mods can see their own inference_results here @@ -186,7 +150,7 @@ pub async fn delete_tts_model_handler( Ok(_) => {}, Err(err) => { warn!("Delete tts model DB error: {:?}", err); - return Err(DeleteTtsModelError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_result.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_result.rs index a2c5e4ab38..abad0907bf 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_result.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/delete_tts_result.rs @@ -14,6 +14,7 @@ use mysql_queries::queries::tts::tts_results::delete_tts_result_various_scopes:: use mysql_queries::queries::tts::tts_results::query_tts_result::select_tts_result_by_token; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_success_helpers::simple_json_success; use crate::state::server_state::ServerState; use crate::util::delete_role_disambiguation::delete_role_disambiguation; @@ -31,64 +32,27 @@ pub struct DeleteTtsInferenceResultRequest { /// NB: this is only to disambiguate when a user is both a mod and an author. as_mod: Option, } - -#[derive(Debug)] -pub enum DeleteTtsInferenceResultError { - BadInput(String), - NotAuthorized, - NotFound, - ServerError, -} - -impl ResponseError for DeleteTtsInferenceResultError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteTtsInferenceResultError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteTtsInferenceResultError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteTtsInferenceResultError::NotFound => StatusCode::NOT_FOUND, - DeleteTtsInferenceResultError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - DeleteTtsInferenceResultError::BadInput(reason) => reason.to_string(), - DeleteTtsInferenceResultError::NotAuthorized => "unauthorized".to_string(), - DeleteTtsInferenceResultError::NotFound => "not found".to_string(), - DeleteTtsInferenceResultError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteTtsInferenceResultError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn delete_tts_inference_result_handler( http_request: HttpRequest, path: Path, request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteTtsInferenceResultError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteTtsInferenceResultError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -105,9 +69,9 @@ pub async fn delete_tts_inference_result_handler( let tts_inference_result = match inference_result_query_result { Err(e) => { warn!("query error: {:?}", e); - return Err(DeleteTtsInferenceResultError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } - Ok(None) => return Err(DeleteTtsInferenceResultError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Ok(Some(inference_result)) => inference_result, }; @@ -121,7 +85,7 @@ pub async fn delete_tts_inference_result_handler( if !is_author && !is_mod { warn!("user is not allowed to delete inference results: {:?}", user_session.user_token); - return Err(DeleteTtsInferenceResultError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let delete_role = delete_role_disambiguation(is_mod, is_author, request.as_mod); @@ -130,7 +94,7 @@ pub async fn delete_tts_inference_result_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to delete inference results: {:?}", user_session.user_token); - return Err(DeleteTtsInferenceResultError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { delete_tts_inference_result_as_user( @@ -150,7 +114,7 @@ pub async fn delete_tts_inference_result_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to undelete inference results: {:?}", user_session.user_token); - return Err(DeleteTtsInferenceResultError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { // NB: Technically only mods can see their own inference_results here @@ -173,7 +137,7 @@ pub async fn delete_tts_inference_result_handler( Ok(_) => {}, Err(err) => { warn!("Update tts mod approval status DB error: {:?}", err); - return Err(DeleteTtsInferenceResultError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_pending_tts_inference_job_count.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_pending_tts_inference_job_count.rs index 83b7f7d7f2..f96e32f55e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_pending_tts_inference_job_count.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_pending_tts_inference_job_count.rs @@ -8,6 +8,7 @@ use log::{debug, error, warn}; use mysql_queries::queries::tts::tts_inference_jobs::get_pending_tts_inference_job_count::get_pending_tts_inference_job_count; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize)] @@ -20,40 +21,11 @@ pub struct Response { /// During an attack, we may want this to go extremely slow. pub refresh_interval_millis: u64, } - - -#[derive(Debug)] -pub enum GetPendingTtsInferenceJobCountError { - ServerError, -} - -impl ResponseError for GetPendingTtsInferenceJobCountError { - fn status_code(&self) -> StatusCode { - match *self { - GetPendingTtsInferenceJobCountError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetPendingTtsInferenceJobCountError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetPendingTtsInferenceJobCountError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_pending_tts_inference_job_count_handler( http_request: HttpRequest, server_state: web::Data> -) -> Result { +) -> Result { if server_state.flags.disable_tts_queue_length_endpoint { // NB: Despite the cache being a powerful protector of the database (this is an expensive query), @@ -70,7 +42,7 @@ pub async fn get_pending_tts_inference_job_count_handler( let maybe_cached = server_state.caches.ephemeral.tts_queue_length.grab_copy_without_bump_if_unexpired() .map_err(|e| { error!("error consulting cache: {:?}", e); - GetPendingTtsInferenceJobCountError::ServerError + CommonWebError::from_anyhow_error(e) })?; let count_result = match maybe_cached { @@ -93,12 +65,12 @@ pub async fn get_pending_tts_inference_job_count_handler( let maybe_cached = server_state.caches.ephemeral.tts_queue_length.grab_even_expired_and_bump() .map_err(|err| { error!("error consulting cache (even expired): {:?}", err); - GetPendingTtsInferenceJobCountError::ServerError + CommonWebError::from_anyhow_error(err) })?; maybe_cached.ok_or_else(|| { error!("error querying database and subsequently reading cache: {:?}", err); - GetPendingTtsInferenceJobCountError::ServerError + CommonWebError::server_error_with_message("uncaught server error") })? } @@ -107,7 +79,7 @@ pub async fn get_pending_tts_inference_job_count_handler( server_state.caches.ephemeral.tts_queue_length.store_copy(&count_result) .map_err(|e| { error!("error storing cache: {:?}", e); - GetPendingTtsInferenceJobCountError::ServerError + CommonWebError::from_anyhow_error(e) })?; count_result @@ -124,25 +96,25 @@ pub async fn get_pending_tts_inference_job_count_handler( }) } -pub fn render_response_busy(response: Response) -> Result { +pub fn render_response_busy(response: Response) -> Result { let body = render_response_payload(response)?; Ok(HttpResponse::TooManyRequests() .content_type("application/json") .body(body)) } -pub fn render_response_ok(response: Response) -> Result { +pub fn render_response_ok(response: Response) -> Result { let body = render_response_payload(response)?; Ok(HttpResponse::Ok() .content_type("application/json") .body(body)) } -pub fn render_response_payload(response: Response) -> Result { +pub fn render_response_payload(response: Response) -> Result { let body = serde_json::to_string(&response) .map_err(|e| { error!("error returning response: {:?}", e); - GetPendingTtsInferenceJobCountError::ServerError + CommonWebError::from_error(e) })?; Ok(body) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs index d5e2cb66e8..b6a2260fa3 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs @@ -16,6 +16,7 @@ use redis_common::redis_keys::RedisKeys; use tokens::tokens::generic_inference_jobs::InferenceJobToken; use crate::http_server::web_utils::filter_model_name::filter_model_name; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::state::server_state::ServerState; @@ -56,49 +57,18 @@ pub struct GetTtsInferenceStatusSuccessResponse { pub success: bool, pub state: TtsInferenceJobStatusForResponse, } - -#[derive(Debug)] -pub enum GetTtsInferenceStatusError { - ServerError, - NotFound, -} - -impl ResponseError for GetTtsInferenceStatusError { - fn status_code(&self) -> StatusCode { - match *self { - GetTtsInferenceStatusError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetTtsInferenceStatusError::NotFound => StatusCode::NOT_FOUND, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - Self::ServerError => "server error".to_string(), - Self::NotFound => "not found".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetTtsInferenceStatusError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_tts_inference_job_status_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let job_token = path.into_inner().token; if job_token.trim() == "None" { // NB: A bunch of Python clients use our API and can fail in this manner. // This was a large traffic driver during the 2023-03-08 outage. - return Err(GetTtsInferenceStatusError::NotFound); + return Err(CommonWebError::NotFound); } // NB(bt,2023-11-27): We're moving TT2 over to `inference-job` (from `tts-inference-job`), which @@ -118,7 +88,7 @@ pub async fn get_tts_inference_job_status_handler( let body = serde_json::to_string(&response) .map_err(|e| { error!("error returning response: {:?}", e); - GetTtsInferenceStatusError::ServerError + CommonWebError::from_error(e) })?; Ok(HttpResponse::Ok() @@ -127,7 +97,7 @@ pub async fn get_tts_inference_job_status_handler( } async fn legacy_lookup(job_token: &str, server_state: &ServerState) - -> Result + -> Result { // NB: Lookup failure is Err(RowNotFound). // NB: Since this is publicly exposed, we don't query sensitive data. @@ -136,10 +106,10 @@ async fn legacy_lookup(job_token: &str, server_state: &ServerState) let record = match maybe_status { Ok(Some(record)) => record, - Ok(None) => return Err(GetTtsInferenceStatusError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { error!("tts job query error: {:?}", err); - return Err(GetTtsInferenceStatusError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -147,7 +117,7 @@ async fn legacy_lookup(job_token: &str, server_state: &ServerState) .get() .map_err(|e| { error!("redis error: {:?}", e); - GetTtsInferenceStatusError::ServerError + CommonWebError::from_error(e) })?; // TODO(bt,2023-05-21): Make async. @@ -180,7 +150,7 @@ async fn legacy_lookup(job_token: &str, server_state: &ServerState) } async fn modern_lookup(job_token: &str, server_state: &ServerState) - -> Result + -> Result { // NB: Lookup failure is Err(RowNotFound). // NB: Since this is publicly exposed, we don't query sensitive data. @@ -193,10 +163,10 @@ async fn modern_lookup(job_token: &str, server_state: &ServerState) let record = match maybe_status { Ok(Some(record)) => record, - Ok(None) => return Err(GetTtsInferenceStatusError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { error!("tts job query error: {:?}", err); - return Err(GetTtsInferenceStatusError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -204,7 +174,7 @@ async fn modern_lookup(job_token: &str, server_state: &ServerState) .get() .map_err(|e| { error!("redis error: {:?}", e); - GetTtsInferenceStatusError::ServerError + CommonWebError::from_error(e) })?; // TODO(bt,2023-05-21): Make async. diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs index 16f882b95b..00824be2c0 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs @@ -3,21 +3,18 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Path; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use log::warn; use crate::http_server::common_responses::user_avatars::default_avatar_color_from_username::default_avatar_color_from_username; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::user_avatars::default_avatar_from_username::default_avatar_from_username; use enums::by_table::tts_models::tts_model_type::TtsModelType; use enums::common::visibility::Visibility; -use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use migration::text_to_speech::get_tts_model_info_migration::get_tts_model_info_migration; use mysql_queries::column_types::vocoder_type::VocoderType; use redis_common::redis_cache_keys::RedisCacheKeys; @@ -149,45 +146,19 @@ pub struct TtsModelModeratorFieldInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum GetTtsModelError { - ServerError, - NotFound, -} - -impl ResponseError for GetTtsModelError { - fn status_code(&self) -> StatusCode { - match *self { - GetTtsModelError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetTtsModelError::NotFound => StatusCode::NOT_FOUND, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetTtsModelError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn get_tts_model_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { warn!("Could not acquire DB pool: {:?}", e); - GetTtsModelError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -196,7 +167,7 @@ pub async fn get_tts_model_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetTtsModelError::ServerError + CommonWebError::from_error(e) })?; let mut show_deleted_models = false; @@ -244,9 +215,9 @@ pub async fn get_tts_model_handler( let model = match model_query_result { Err(e) => { warn!("query error: {:?}", e); - return Err(GetTtsModelError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } - Ok(None) => return Err(GetTtsModelError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Ok(Some(model)) => model, }; @@ -259,7 +230,7 @@ pub async fn get_tts_model_handler( // // NB: The moderator fields will always be present before removal // // We don't want non-mods seeing stuff made by banned users. // if moderator_fields.creator_is_banned && !is_moderator { - // return Err(GetTtsModelError::NotFound); + // return Err(CommonWebError::NotFound); // } //} @@ -357,7 +328,7 @@ pub async fn get_tts_model_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| GetTtsModelError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_result.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_result.rs index 1f266534a4..bd7a0283ad 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_result.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_result.rs @@ -11,6 +11,7 @@ use mysql_queries::queries::tts::tts_results::query_tts_result::select_tts_resul use mysql_queries::queries::tts::tts_results::query_tts_result::TtsResultRecordForResponse; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -24,42 +25,11 @@ pub struct GetTtsResultSuccessResponse { pub success: bool, pub result: TtsResultRecordForResponse, } - -#[derive(Debug)] -pub enum GetTtsResultError { - ServerError, - NotFound, -} - -impl ResponseError for GetTtsResultError { - fn status_code(&self) -> StatusCode { - match *self { - GetTtsResultError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - GetTtsResultError::NotFound=> StatusCode::NOT_FOUND, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetTtsResultError::ServerError => "server error".to_string(), - GetTtsResultError::NotFound => "not found".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for GetTtsResultError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn get_tts_inference_result_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -67,7 +37,7 @@ pub async fn get_tts_inference_result_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetTtsResultError::ServerError + CommonWebError::from_error(e) })?; let mut show_deleted_results = false; @@ -91,9 +61,9 @@ pub async fn get_tts_inference_result_handler( let mut inference_result = match inference_result_query_result { Err(e) => { warn!("query error: {:?}", e); - return Err(GetTtsResultError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } - Ok(None) => return Err(GetTtsResultError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Ok(Some(inference_result)) => inference_result, }; @@ -102,7 +72,7 @@ pub async fn get_tts_inference_result_handler( // We don't want non-mods seeing stuff made by banned users. if (moderator_fields.model_creator_is_banned || moderator_fields.result_creator_is_banned_if_user) && !is_moderator{ - return Err(GetTtsResultError::NotFound); + return Err(CommonWebError::NotFound); } } @@ -116,7 +86,7 @@ pub async fn get_tts_inference_result_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetTtsResultError::ServerError)?; + .map_err(|e| CommonWebError::from_error(e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_upload_model_job_status.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_upload_model_job_status.rs index f6ad08064e..a2dd7ddf90 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_upload_model_job_status.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_upload_model_job_status.rs @@ -13,6 +13,7 @@ use mysql_queries::queries::tts::tts_model_upload_jobs::get_tts_model_upload_job use redis_common::redis_keys::RedisKeys; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -45,50 +46,28 @@ pub struct GetTtsUploadModelStatusSuccessResponse { pub success: bool, pub state: TtsUploadModelJobStatusForResponse, } - -#[derive(Debug, Display)] -pub enum GetTtsUploadModelStatusError { - ServerError, -} - -impl ResponseError for GetTtsUploadModelStatusError { - fn status_code(&self) -> StatusCode { - match *self { - GetTtsUploadModelStatusError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - GetTtsUploadModelStatusError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - pub async fn get_tts_upload_model_job_status_handler( http_request: HttpRequest, path: Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { // NB: Since this is publicly exposed, we don't query sensitive data. let record = get_tts_model_upload_job_status(&path.token, &server_state.mysql_pool) .await .map_err(|err| { error!("tts template query error: {:?}", err); - GetTtsUploadModelStatusError::ServerError + CommonWebError::from_anyhow_error(err) })? .ok_or( // TODO: 404 - GetTtsUploadModelStatusError::ServerError + CommonWebError::server_error_with_message("uncaught server error") )?; let mut redis = server_state.redis_pool .get() .map_err(|e| { warn!("redis error: {:?}", e); - GetTtsUploadModelStatusError::ServerError + CommonWebError::from_error(e) })?; let extra_status_key = RedisKeys::tts_download_extra_status_info(&path.token); @@ -119,7 +98,7 @@ pub async fn get_tts_upload_model_job_status_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetTtsUploadModelStatusError::ServerError)?; + .map_err(|e| CommonWebError::from_error(e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_tts_models.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_tts_models.rs index 867b5a95b5..24aca909e6 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_tts_models.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_tts_models.rs @@ -4,11 +4,8 @@ #![forbid(unused_variables)] use std::collections::HashSet; -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use lexical_sort::natural_lexical_cmp; @@ -23,7 +20,7 @@ use migration::text_to_speech::list_tts_models_for_migration::list_tts_models_fo use mysql_queries::queries::tts::tts_category_assignments::fetch_and_build_tts_model_category_map::fetch_and_build_tts_model_category_map_with_connection; use mysql_queries::queries::users::user_sessions::get_user_session_by_token::SessionUserRecord; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize, Clone)] @@ -66,38 +63,10 @@ pub struct ListTtsModelsSuccessResponse { pub success: bool, pub models: Vec, } - -#[derive(Debug)] -pub enum ListTtsModelsError { - ServerError, -} - -impl ResponseError for ListTtsModelsError { - fn status_code(&self) -> StatusCode { - match *self { - ListTtsModelsError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListTtsModelsError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTtsModelsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_tts_models_handler( http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { if server_state.flags.disable_tts_model_list_endpoint { // NB: Despite the cache being a powerful protector of the database (this is an expensive query), @@ -112,7 +81,7 @@ pub async fn list_tts_models_handler( let maybe_models = server_state.caches.ephemeral.tts_model_list.grab_copy_without_bump_if_unexpired() .map_err(|e| { error!("Error consulting cache: {:?}", e); - ListTtsModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; // NB: We don't know if we need a MySQL connection, so don't grab one unless we do. @@ -130,7 +99,7 @@ pub async fn list_tts_models_handler( .await .map_err(|e| { warn!("Could not acquire DB pool: {:?}", e); - ListTtsModelsError::ServerError + CommonWebError::from_error(e) })?; // TODO: Fail open in case the DB is down. Pull from expired cache if query fails. @@ -138,7 +107,7 @@ pub async fn list_tts_models_handler( .await .map_err(|e| { error!("Error querying database: {:?}", e); - ListTtsModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; maybe_mysql_connection = Some(mysql_connection); @@ -146,7 +115,7 @@ pub async fn list_tts_models_handler( server_state.caches.ephemeral.tts_model_list.store_copy(&models) .map_err(|e| { error!("Error storing cache: {:?}", e); - ListTtsModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; models @@ -166,7 +135,7 @@ pub async fn list_tts_models_handler( } }.map_err(|e| { warn!("Session checker error: {:?}", e); - ListTtsModelsError::ServerError + CommonWebError::from_error(e) })?; let maybe_session_user_token = maybe_user_session @@ -190,25 +159,25 @@ pub async fn list_tts_models_handler( }) } -pub fn render_response_busy(response: ListTtsModelsSuccessResponse) -> Result { +pub fn render_response_busy(response: ListTtsModelsSuccessResponse) -> Result { let body = render_response_payload(response)?; Ok(HttpResponse::TooManyRequests() .content_type("application/json") .body(body)) } -pub fn render_response_ok(response: ListTtsModelsSuccessResponse) -> Result { +pub fn render_response_ok(response: ListTtsModelsSuccessResponse) -> Result { let body = render_response_payload(response)?; Ok(HttpResponse::Ok() .content_type("application/json") .body(body)) } -pub fn render_response_payload(response: ListTtsModelsSuccessResponse) -> Result { +pub fn render_response_payload(response: ListTtsModelsSuccessResponse) -> Result { let body = serde_json::to_string(&response) .map_err(|e| { error!("error returning response: {:?}", e); - ListTtsModelsError::ServerError + CommonWebError::from_error(e) })?; Ok(body) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_inference_results.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_inference_results.rs index 8f6f47d7a8..247e65ac4b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_inference_results.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_inference_results.rs @@ -11,6 +11,7 @@ use log::warn; use mysql_queries::queries::tts::tts_results::list_tts_results_query_builder::{ListTtsResultsQueryBuilder, TtsInferenceRecordForList}; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -34,41 +35,13 @@ pub struct ListTtsInferenceResultsForUserSuccessResponse { pub cursor_next: Option, pub cursor_previous: Option, } - -#[derive(Debug)] -pub enum ListTtsInferenceResultsForUserError { - ServerError, -} - -impl ResponseError for ListTtsInferenceResultsForUserError { - fn status_code(&self) -> StatusCode { - match *self { - ListTtsInferenceResultsForUserError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListTtsInferenceResultsForUserError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTtsInferenceResultsForUserError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_user_tts_inference_results_handler( http_request: HttpRequest, path: Path, query: Query, server_state: web::Data> -) -> Result +) -> Result { return Ok(HttpResponse::Gone() .content_type(ContentType::plaintext()) @@ -80,7 +53,7 @@ pub async fn list_user_tts_inference_results_handler( path: Path, query: Query, server_state: web::Data> - ) -> Result + ) -> Result { let maybe_user_session = server_state .session_checker @@ -88,7 +61,7 @@ pub async fn list_user_tts_inference_results_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListTtsInferenceResultsForUserError::ServerError + CommonWebError::from_error(e) })?; // Permissions & ACLs @@ -114,7 +87,7 @@ pub async fn list_user_tts_inference_results_handler( let cursor = server_state.sort_key_crypto.decrypt_id(cursor) .map_err(|e| { warn!("crypto error: {:?}", e); - ListTtsInferenceResultsForUserError::ServerError + CommonWebError::from_anyhow_error(e) })?; Some(cursor) } else { @@ -139,7 +112,7 @@ pub async fn list_user_tts_inference_results_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListTtsInferenceResultsForUserError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -147,7 +120,7 @@ pub async fn list_user_tts_inference_results_handler( let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) .map_err(|e| { warn!("crypto error: {:?}", e); - ListTtsInferenceResultsForUserError::ServerError + CommonWebError::from_anyhow_error(e) })?; Some(cursor) } else { @@ -158,7 +131,7 @@ pub async fn list_user_tts_inference_results_handler( let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) .map_err(|e| { warn!("crypto error: {:?}", e); - ListTtsInferenceResultsForUserError::ServerError + CommonWebError::from_anyhow_error(e) })?; Some(cursor) } else { @@ -173,7 +146,7 @@ pub async fn list_user_tts_inference_results_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListTtsInferenceResultsForUserError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_models.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_models.rs index 328b96c40b..94e892b150 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_models.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/list_user_tts_models.rs @@ -11,6 +11,7 @@ use log::{info, warn}; use mysql_queries::queries::tts::tts_models::list_tts_models::{list_tts_models, TtsModelRecordForList}; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; /// For the URL PathInfo @@ -24,40 +25,12 @@ pub struct ListTtsModelsForUserSuccessResponse { pub success: bool, pub models: Vec, } - -#[derive(Debug)] -pub enum ListTtsModelsForUserError { - ServerError, -} - -impl ResponseError for ListTtsModelsForUserError { - fn status_code(&self) -> StatusCode { - match *self { - ListTtsModelsForUserError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListTtsModelsForUserError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListTtsModelsForUserError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_user_tts_models_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result +) -> Result { return Ok(HttpResponse::Gone() .content_type(ContentType::plaintext()) @@ -68,7 +41,7 @@ pub async fn original_list_user_tts_models_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result +) -> Result { info!("Fetching templates for user: {}", &path.username); @@ -82,7 +55,7 @@ pub async fn original_list_user_tts_models_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListTtsModelsForUserError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -92,7 +65,7 @@ pub async fn original_list_user_tts_models_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListTtsModelsForUserError::ServerError)?; + .map_err(|e| CommonWebError::from_error(e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/search_tts_models_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/search_tts_models_handler.rs index da122215b5..93878e9a6e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/search_tts_models_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/search_tts_models_handler.rs @@ -4,11 +4,8 @@ #![forbid(unused_variables)] use std::collections::HashSet; -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use log::error; @@ -18,7 +15,7 @@ use enums::common::visibility::Visibility; use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::users::UserToken; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Deserialize)] @@ -66,39 +63,11 @@ pub struct SearchTtsModelsSuccessResponse { pub success: bool, pub models: Vec, } - -#[derive(Debug)] -pub enum SearchTtsModelsError { - ServerError, -} - -impl ResponseError for SearchTtsModelsError { - fn status_code(&self) -> StatusCode { - match *self { - SearchTtsModelsError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - SearchTtsModelsError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for SearchTtsModelsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn search_tts_models_handler( _http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let results = search_tts_models( &server_state.elasticsearch, @@ -107,7 +76,7 @@ pub async fn search_tts_models_handler( .await .map_err(|err| { error!("Searching error: {:?}", err); - SearchTtsModelsError::ServerError + CommonWebError::from_anyhow_error(err) })?; let results = results.into_iter() @@ -146,7 +115,7 @@ pub async fn search_tts_models_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| SearchTtsModelsError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/batch_get_user_rating_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/batch_get_user_rating_handler.rs index 60d8da4dc6..cb9d2aee7b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/batch_get_user_rating_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/batch_get_user_rating_handler.rs @@ -16,6 +16,7 @@ use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; const MAX_BATCH_SIZE : usize = 200; @@ -55,35 +56,7 @@ pub struct RatingRow { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum BatchGetUserRatingError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for BatchGetUserRatingError { - fn status_code(&self) -> StatusCode { - match *self { - BatchGetUserRatingError::BadInput(_) => StatusCode::BAD_REQUEST, - BatchGetUserRatingError::NotAuthorized => StatusCode::UNAUTHORIZED, - BatchGetUserRatingError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl std::fmt::Display for BatchGetUserRatingError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== @@ -96,21 +69,21 @@ impl std::fmt::Display for BatchGetUserRatingError { ), responses( (status = 200, description = "List User Bookmarks", body = BatchGetUserRatingResponse), - (status = 400, description = "Bad input", body = BatchGetUserRatingError), - (status = 401, description = "Not authorized", body = BatchGetUserRatingError), - (status = 500, description = "Server error", body = BatchGetUserRatingError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn batch_get_user_rating_handler( http_request: HttpRequest, query: Query, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { error!("Could not acquire DB pool: {:?}", e); - BatchGetUserRatingError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -119,7 +92,7 @@ pub async fn batch_get_user_rating_handler( .await .map_err(|e| { error!("Session checker error: {:?}", e); - BatchGetUserRatingError::ServerError + CommonWebError::from_error(e) })?; // NB: Force move of tokens from the Query. @@ -151,7 +124,7 @@ pub async fn batch_get_user_rating_handler( ).await .map_err(|e| { error!("Batch get user ratings DB error: {:?}", e); - BatchGetUserRatingError::ServerError + CommonWebError::from_anyhow_error(e) }) .map(|ratings| { HttpResponse::Ok() diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs index 1865ed40f0..39d5c5852b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs @@ -16,6 +16,7 @@ use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::w2l_templates::W2lTemplateToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -41,35 +42,7 @@ pub struct GetUserRatingResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum GetUserRatingError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for GetUserRatingError { - fn status_code(&self) -> StatusCode { - match *self { - GetUserRatingError::BadInput(_) => StatusCode::BAD_REQUEST, - GetUserRatingError::NotAuthorized => StatusCode::UNAUTHORIZED, - GetUserRatingError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl std::fmt::Display for GetUserRatingError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== @@ -83,21 +56,21 @@ impl std::fmt::Display for GetUserRatingError { ), responses( (status = 200, description = "List User Bookmarks", body = GetUserRatingResponse), - (status = 400, description = "Bad input", body = GetUserRatingError), - (status = 401, description = "Not authorized", body = GetUserRatingError), - (status = 500, description = "Server error", body = GetUserRatingError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn get_user_rating_handler( http_request: HttpRequest, path: web::Path, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { error!("Could not acquire DB pool: {:?}", e); - GetUserRatingError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -106,14 +79,14 @@ pub async fn get_user_rating_handler( .await .map_err(|e| { error!("Session checker error: {:?}", e); - GetUserRatingError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { info!("not logged in"); - return Err(GetUserRatingError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -129,7 +102,7 @@ pub async fn get_user_rating_handler( // TODO: We'll handle ratings of more types in the future. UserRatingEntityType::W2lResult | UserRatingEntityType::TtsResult => - return Err(GetUserRatingError::BadInput("type not yet supported".to_string())), + return Err(CommonWebError::BadInputWithSimpleMessage("type not yet supported".to_string())), }; let maybe_rating = get_user_rating(Args { @@ -140,7 +113,7 @@ pub async fn get_user_rating_handler( .await .map_err(|err| { error!("Error fetching rating: {:?}", err); - GetUserRatingError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = GetUserRatingResponse { @@ -149,7 +122,7 @@ pub async fn get_user_rating_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| GetUserRatingError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs index b5fbe5cc97..5d3fc88b9b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs @@ -25,6 +25,7 @@ use tokens::tokens::w2l_results::W2lResultToken; use tokens::tokens::w2l_templates::W2lTemplateToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -51,35 +52,7 @@ pub struct SetUserRatingResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum SetUserRatingError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for SetUserRatingError { - fn status_code(&self) -> StatusCode { - match *self { - SetUserRatingError::BadInput(_) => StatusCode::BAD_REQUEST, - SetUserRatingError::NotAuthorized => StatusCode::UNAUTHORIZED, - SetUserRatingError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl std::fmt::Display for SetUserRatingError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== #[utoipa::path( @@ -89,15 +62,15 @@ impl std::fmt::Display for SetUserRatingError { request_body = SetUserRatingRequest, responses( (status = 200, description = "Set user rating", body = SetUserRatingResponse), - (status = 400, description = "Bad input", body = SetUserRatingError), - (status = 401, description = "Not authorized", body = SetUserRatingError), - (status = 500, description = "Server error", body = SetUserRatingError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn set_user_rating_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from // querying the database for entity existence, this is the next best way to prevent incorrect comment @@ -117,14 +90,14 @@ pub async fn set_user_rating_handler( if !token_prefix_matches { warn!("invalid token prefix: {:?} for {:?}", request.entity_token, request.entity_type); - return Err(SetUserRatingError::BadInput("invalid token prefix".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("invalid token prefix".to_string())); } let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { error!("Could not acquire DB pool: {:?}", e); - SetUserRatingError::ServerError + CommonWebError::from_error(e) })?; let maybe_user_session = server_state @@ -133,14 +106,14 @@ pub async fn set_user_rating_handler( .await .map_err(|e| { error!("Session checker error: {:?}", e); - SetUserRatingError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { info!("not logged in"); - return Err(SetUserRatingError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -158,13 +131,13 @@ pub async fn set_user_rating_handler( // TODO: We'll handle ratings of more types in the future. UserRatingEntityType::W2lResult | UserRatingEntityType::TtsResult => - return Err(SetUserRatingError::BadInput("type not yet supported".to_string())), + return Err(CommonWebError::BadInputWithSimpleMessage("type not yet supported".to_string())), }; let mut transaction = mysql_connection.begin().await .map_err(|err| { error!("error creating transaction: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_error(err) })?; let maybe_existing_user_rating = get_user_rating_transactional_locking( @@ -174,7 +147,7 @@ pub async fn set_user_rating_handler( ).await .map_err(|err| { error!("error getting user rating: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_anyhow_error(err) })?; let _r = upsert_user_rating(Args { @@ -188,7 +161,7 @@ pub async fn set_user_rating_handler( .await .map_err(|err| { error!("Error upserting rating: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_anyhow_error(err) })?; let existing_rating_value = maybe_existing_user_rating @@ -224,7 +197,7 @@ pub async fn set_user_rating_handler( .await .map_err(|err| { error!("Error upserting entity stats: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_anyhow_error(err) })?; } } @@ -232,7 +205,7 @@ pub async fn set_user_rating_handler( transaction.commit().await .map_err(|err| { error!("error committing transaction: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_error(err) })?; // NB: Legacy @@ -243,7 +216,7 @@ pub async fn set_user_rating_handler( .await .map_err(|err| { error!("Error updating TTS rating summary stats: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_anyhow_error(err) })?; } _ => { @@ -258,7 +231,7 @@ pub async fn set_user_rating_handler( .await .map_err(|err| { error!("Error getting total user rating count for entity: {:?}", err); - SetUserRatingError::ServerError + CommonWebError::from_anyhow_error(err) })?; let response = SetUserRatingResponse { @@ -267,7 +240,7 @@ pub async fn set_user_rating_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| SetUserRatingError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/change_password_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/change_password_handler.rs index b04581b09f..94d837d448 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/change_password_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/change_password_handler.rs @@ -3,60 +3,21 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Json; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; use log::warn; -use utoipa::ToSchema; use artcraft_api_defs::users::change_password::{ChangePasswordRequest, ChangePasswordResponse}; use crate::http_server::validations::validate_passwords::validate_passwords; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_user_session_extended_using_connection::require_user_session_extended_using_connection; use crate::state::server_state::ServerState; use http_server_common::request::get_request_ip::get_request_ip; use mysql_queries::queries::users::user::update::update_password::{update_password, UpdatePasswordArgs}; use mysql_queries::utils::transactor::Transactor; use password::bcrypt_hash_password::bcrypt_hash_password; - -#[derive(Debug, ToSchema)] -pub enum ChangePasswordError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for ChangePasswordError { - fn status_code(&self) -> StatusCode { - match *self { - ChangePasswordError::BadInput(_) => StatusCode::BAD_REQUEST, - ChangePasswordError::NotAuthorized => StatusCode::UNAUTHORIZED, - ChangePasswordError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ChangePasswordError::BadInput(reason) => reason.to_string(), - ChangePasswordError::NotAuthorized => "unauthorized".to_string(), - ChangePasswordError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ChangePasswordError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - - /// Change password for the current user. #[utoipa::path( post, @@ -64,9 +25,9 @@ impl fmt::Display for ChangePasswordError { path = "/v1/user/change_password", responses( (status = 200, description = "Success", body = ChangePasswordResponse), - (status = 400, description = "Bad input", body = ChangePasswordError), - (status = 401, description = "Not authorized", body = ChangePasswordError), - (status = 500, description = "Server error", body = ChangePasswordError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = ChangePasswordRequest, description = "Payload for Request"), @@ -76,13 +37,13 @@ pub async fn change_password_handler( http_request: HttpRequest, request: Json, server_state: web::Data>, -) -> Result, ChangePasswordError> +) -> Result, CommonWebError> { let password = request.password.trim(); let password_confirmation = request.password_confirmation.trim(); if let Err(reason) = validate_passwords(password, password_confirmation) { - return Err(ChangePasswordError::BadInput(reason)); + return Err(CommonWebError::BadInputWithSimpleMessage(reason)); } let mut mysql_connection = server_state.mysql_pool @@ -90,7 +51,7 @@ pub async fn change_password_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - ChangePasswordError::ServerError + CommonWebError::from_error(err) })?; let user_session = require_user_session_extended_using_connection( @@ -99,18 +60,18 @@ pub async fn change_password_handler( &mut mysql_connection) .await .map_err(|_err| { - ChangePasswordError::NotAuthorized + CommonWebError::NotAuthorized })?; if user_session.role.is_banned { - return Err(ChangePasswordError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let password_hash = match bcrypt_hash_password(password.to_string()) { Ok(hash) => hash, Err(err) => { warn!("Bcrypt error: {:?}", err); - return Err(ChangePasswordError::ServerError); + return Err(CommonWebError::from_error(err)); } }; @@ -127,7 +88,7 @@ pub async fn change_password_handler( Ok(()) => {}, Err(err) => { warn!("Error updating password: {:?}", err); - return Err(ChangePasswordError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_email_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_email_handler.rs index df4c546c9a..04aabbe751 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_email_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_email_handler.rs @@ -3,17 +3,13 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Json; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; use log::warn; -use utoipa::ToSchema; use artcraft_api_defs::users::edit_email::{EditEmailRequest, EditEmailResponse}; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_user_session_extended_using_connection::require_user_session_extended_using_connection; use crate::state::server_state::ServerState; use http_server_common::request::get_request_ip::get_request_ip; @@ -21,42 +17,7 @@ use mysql_queries::queries::users::user::update::update_email::{update_email, Up use mysql_queries::utils::transactor::Transactor; use users::email::email_to_gravatar_hash::email_to_gravatar_hash; use users::email::validate_email_address_format::validate_email_address_format; - -#[derive(Debug, ToSchema)] -pub enum EditEmailError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for EditEmailError { - fn status_code(&self) -> StatusCode { - match *self { - EditEmailError::BadInput(_) => StatusCode::BAD_REQUEST, - EditEmailError::NotAuthorized => StatusCode::UNAUTHORIZED, - EditEmailError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - EditEmailError::BadInput(reason) => reason.to_string(), - EditEmailError::NotAuthorized => "unauthorized".to_string(), - EditEmailError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditEmailError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - - /// Edit email address of the current user. #[utoipa::path( post, @@ -64,9 +25,9 @@ impl fmt::Display for EditEmailError { path = "/v1/user/edit_email", responses( (status = 200, description = "Success", body = EditEmailResponse), - (status = 400, description = "Bad input", body = EditEmailError), - (status = 401, description = "Not authorized", body = EditEmailError), - (status = 500, description = "Server error", body = EditEmailError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = EditEmailRequest, description = "Payload for Request"), @@ -76,12 +37,12 @@ pub async fn edit_email_handler( http_request: HttpRequest, request: Json, server_state: web::Data>, -) -> Result, EditEmailError> +) -> Result, CommonWebError> { let email_address = request.email_address.trim().to_lowercase(); if let Err(reason) = validate_email_address_format(&email_address) { - return Err(EditEmailError::BadInput(format!("bad email: {}", &reason))); + return Err(CommonWebError::BadInputWithSimpleMessage(format!("bad email: {}", &reason))); } let mut mysql_connection = server_state.mysql_pool @@ -89,7 +50,7 @@ pub async fn edit_email_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - EditEmailError::ServerError + CommonWebError::from_error(err) })?; let user_session = require_user_session_extended_using_connection( @@ -98,11 +59,11 @@ pub async fn edit_email_handler( &mut mysql_connection) .await .map_err(|_err| { - EditEmailError::NotAuthorized + CommonWebError::NotAuthorized })?; if user_session.role.is_banned { - return Err(EditEmailError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let ip_address = get_request_ip(&http_request); @@ -119,11 +80,11 @@ pub async fn edit_email_handler( match result { Ok(()) => {}, Err(UpdateEmailError::EmailIsTaken) => { - return Err(EditEmailError::BadInput("email address is already in use".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("email address is already in use".to_string())); } Err(UpdateEmailError::DatabaseError { source }) => { warn!("Error updating email: {:?}", source); - return Err(EditEmailError::ServerError); + return Err(CommonWebError::server_error_with_message("uncaught server error")); } } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_username_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_username_handler.rs index cbeebe465d..ea6893f340 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_username_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/edit_username_handler.rs @@ -3,61 +3,22 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Json; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; use log::warn; -use utoipa::ToSchema; use artcraft_api_defs::users::edit_username::{EditUsernameRequest, EditUsernameResponse}; use crate::http_server::validations::is_reserved_username::is_reserved_username; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::validations::validate_username::validate_username; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::http_server::web_utils::user_session::require_user_session_extended_using_connection::require_user_session_extended_using_connection; use crate::state::server_state::ServerState; use http_server_common::request::get_request_ip::get_request_ip; use mysql_queries::queries::users::user::update::update_username::{update_username, UpdateUsernameArgs, UpdateUsernameError}; use mysql_queries::utils::transactor::Transactor; use user_input_common::check_for_slurs::contains_slurs; - - -#[derive(Debug, ToSchema)] -pub enum EditUsernameError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for EditUsernameError { - fn status_code(&self) -> StatusCode { - match *self { - EditUsernameError::BadInput(_) => StatusCode::BAD_REQUEST, - EditUsernameError::NotAuthorized => StatusCode::UNAUTHORIZED, - EditUsernameError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - EditUsernameError::BadInput(reason) => reason.to_string(), - EditUsernameError::NotAuthorized => "unauthorized".to_string(), - EditUsernameError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for EditUsernameError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Edit username of the current user. #[utoipa::path( post, @@ -65,9 +26,9 @@ impl fmt::Display for EditUsernameError { path = "/v1/user/edit_username", responses( (status = 200, description = "Success", body = EditUsernameResponse), - (status = 400, description = "Bad input", body = EditUsernameError), - (status = 401, description = "Not authorized", body = EditUsernameError), - (status = 500, description = "Server error", body = EditUsernameError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = EditUsernameRequest, description = "Payload for Request"), @@ -77,21 +38,21 @@ pub async fn edit_username_handler( http_request: HttpRequest, request: Json, server_state: web::Data>, -) -> Result, EditUsernameError> +) -> Result, CommonWebError> { let username = request.display_name.trim().to_lowercase(); let display_name = request.display_name.trim().to_string(); if let Err(reason) = validate_username(&display_name) { - return Err(EditUsernameError::BadInput(format!("bad username: {}", &reason))); + return Err(CommonWebError::BadInputWithSimpleMessage(format!("bad username: {}", &reason))); } if contains_slurs(&username) { - return Err(EditUsernameError::BadInput("username contains slurs".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("username contains slurs".to_string())); } if is_reserved_username(&username) { - return Err(EditUsernameError::BadInput("username is reserved".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("username is reserved".to_string())); } let mut mysql_connection = server_state.mysql_pool @@ -99,7 +60,7 @@ pub async fn edit_username_handler( .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - EditUsernameError::ServerError + CommonWebError::from_error(err) })?; let user_session = require_user_session_extended_using_connection( @@ -108,11 +69,11 @@ pub async fn edit_username_handler( &mut mysql_connection) .await .map_err(|_err| { - EditUsernameError::NotAuthorized + CommonWebError::NotAuthorized })?; if user_session.role.is_banned { - return Err(EditUsernameError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let ip_address = get_request_ip(&http_request); @@ -129,11 +90,11 @@ pub async fn edit_username_handler( match result { Ok(()) => {}, Err(UpdateUsernameError::UsernameIsTaken) => { - return Err(EditUsernameError::BadInput("username is taken".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("username is taken".to_string())); } Err(UpdateUsernameError::DatabaseError { source }) => { warn!("Error updating username: {:?}", source); - return Err(EditUsernameError::ServerError); + return Err(CommonWebError::server_error_with_message("uncaught server error")); } } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/get_profile_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/get_profile_handler.rs index 0ea5f547a5..0e97ffedd8 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/get_profile_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/get_profile_handler.rs @@ -4,10 +4,7 @@ #![forbid(unused_variables)] use std::collections::BTreeSet; -use std::fmt; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::web::Path; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; @@ -20,7 +17,6 @@ use utoipa::ToSchema; use enums::by_table::users::user_feature_flag::UserFeatureFlag; use enums::common::visibility::Visibility; use http_server_common::request::get_request_header_optional::get_request_header_optional; -use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use http_server_common::util::timer::MultiBenchmarkingTimer; use mysql_queries::queries::users::user_badges::list_user_badges::list_user_badges; use mysql_queries::queries::users::user_badges::list_user_badges::UserBadgeForList; @@ -28,6 +24,7 @@ use mysql_queries::queries::users::user_profiles::get_user_profile_by_username:: use tokens::tokens::users::UserToken; use crate::http_server::common_responses::user_avatars::default_avatar_color_from_username::default_avatar_color_from_username; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::user_avatars::default_avatar_from_username::default_avatar_from_username; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags; @@ -89,47 +86,20 @@ pub struct ProfileSuccessResponse { pub success: bool, pub user: Option, } - -#[derive(Debug, Serialize, ToSchema)] -pub enum ProfileError { - ServerError, - NotFound, -} - /// For the URL PathInfo #[derive(Deserialize, ToSchema)] pub struct GetProfilePathInfo { username: String, } - -impl ResponseError for ProfileError { - fn status_code(&self) -> StatusCode { - match *self { - ProfileError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - ProfileError::NotFound => StatusCode::NOT_FOUND, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ProfileError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( get, tag = "Users", path = "/v1/user/{username}/profile", responses( (status = 200, description = "Get profile", body = UserProfileRecordForResponse), - (status = 404, description = "Not found", body = ProfileError), - (status = 500, description = "Server error", body = ProfileError), + (status = 404, description = "Not found", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("path" = GetProfilePathInfo, description = "Path for Request") @@ -141,7 +111,7 @@ pub async fn get_profile_handler( mysql_pool: web::Data, redis_pool: web::Data>, session_checker: web::Data, -) -> Result +) -> Result { let mut benchmark = MultiBenchmarkingTimer::new_started(); @@ -149,7 +119,7 @@ pub async fn get_profile_handler( .await .map_err(|e| { warn!("Could not acquire DB pool: {:?}", e); - ProfileError::ServerError + CommonWebError::from_error(e) })?; let (pool_connection, maybe_user_session_fut) = @@ -159,7 +129,7 @@ pub async fn get_profile_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ProfileError::ServerError + CommonWebError::from_error(e) }); (pc, ret) } @@ -198,10 +168,10 @@ pub async fn get_profile_handler( let user_profile = match maybe_user_profile { Ok(Some(user_profile)) => user_profile, - Ok(None) => return Err(ProfileError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Err(err) => { error!("User profile query error: {:?}", err); - return Err(ProfileError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -227,7 +197,7 @@ pub async fn get_profile_handler( } let user_data = match maybe_user_data { - None => return Err(ProfileError::NotFound), + None => return Err(CommonWebError::NotFound), Some(user_data) => user_data, }; @@ -238,7 +208,7 @@ pub async fn get_profile_handler( if is_banned && !is_mod { // Can't see banned users. - return Err(ProfileError::NotFound); + return Err(CommonWebError::NotFound); } if store_in_cache { @@ -312,7 +282,7 @@ pub async fn get_profile_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ProfileError::ServerError)?; + .map_err(CommonWebError::from_error)?; let mut http_response = HttpResponse::Ok(); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/logout_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/logout_handler.rs index 8852748255..ca15e7c7ce 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/logout_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/logout_handler.rs @@ -3,13 +3,10 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; +use crate::http_server::common_responses::common_web_error::CommonWebError; use actix_artcraft::sessions::user_sessions::http_user_session_manager::HttpUserSessionManager; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; -use http_server_common::response::response_error_helpers::to_simple_json_error; use log::warn; use mysql_queries::queries::users::user_sessions::delete_user_session::delete_user_session; use sqlx::MySqlPool; @@ -20,42 +17,14 @@ use utoipa::ToSchema; pub struct LogoutSuccessResponse { pub success: bool, } - -#[derive(Debug, ToSchema)] -pub enum LogoutError { - ServerError, -} - -impl ResponseError for LogoutError { - fn status_code(&self) -> StatusCode { - match *self { - LogoutError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - LogoutError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for LogoutError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( post, tag = "Users", path = "/v1/logout", responses( (status = 200, description = "Found", body = LogoutSuccessResponse), - (status = 500, description = "Server error", body = LogoutError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn logout_handler( @@ -63,7 +32,7 @@ pub async fn logout_handler( session_cookie_manager: web::Data, mysql_pool: web::Data, internal_session_cache_purge: web::Data, -) -> Result +) -> Result { // Best effort to delete Redis session cache internal_session_cache_purge.best_effort_purge_session_cache(&http_request); @@ -72,7 +41,7 @@ pub async fn logout_handler( .decode_session_payload_from_request(&http_request) .map_err(|e| { warn!("Session cookie decode error: {:?}", e); - LogoutError::ServerError + CommonWebError::from_error(e) })?; if let Some(session) = maybe_session { @@ -93,7 +62,7 @@ pub async fn logout_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| LogoutError::ServerError)?; + .map_err(CommonWebError::from_error)?; // Mark cookie for deletion delete_cookie.make_removal(); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_token_info_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_token_info_handler.rs index a027d6fc0c..3b40181675 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_token_info_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_token_info_handler.rs @@ -11,6 +11,7 @@ use utoipa::ToSchema; use http_server_common::response::response_error_helpers::to_simple_json_error; use crate::http_server::session::session_checker::SessionChecker; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Serialize, ToSchema)] @@ -21,38 +22,7 @@ pub struct SessionTokenInfoSuccessResponse { /// Send this as the "Session:" header. pub maybe_signed_session: Option, } - -#[derive(Debug, ToSchema)] -pub enum SessionTokenInfoError { - NotAuthorized, - ServerError, -} - -impl ResponseError for SessionTokenInfoError { - fn status_code(&self) -> StatusCode { - match *self { - SessionTokenInfoError::NotAuthorized => StatusCode::UNAUTHORIZED, - SessionTokenInfoError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - SessionTokenInfoError::ServerError => "server error".to_string(), - SessionTokenInfoError::NotAuthorized => "not authorized".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for SessionTokenInfoError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - /// Hack to bypass CORS. !!!!!!!!!!!DO NOT USE THIS!!!!!!!!!!!!!! /// /// Seriously do not use this unless you okay it with Brandon, Kasisnu, or Michael. @@ -63,21 +33,21 @@ impl fmt::Display for SessionTokenInfoError { path = "/v1/session_token", responses( (status = 200, description = "Success response", body = SessionTokenInfoSuccessResponse), - (status = 500, description = "Server error", body = SessionTokenInfoError), + (status = 500, description = "Server error", body = CommonWebError), ), )] pub async fn session_token_info_handler( http_request: HttpRequest, session_checker: web::Data, server_state: web::Data>, -) -> Result, SessionTokenInfoError> +) -> Result, CommonWebError> { let maybe_session_payload = server_state .session_cookie_manager .check_and_return_session_token_decodes(&http_request) .map_err(|e| { warn!("Session cookie decode error: {:?}", e); - SessionTokenInfoError::ServerError + CommonWebError::from_error(e) })?; Ok(Json(SessionTokenInfoSuccessResponse { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/check_if_voice_clone_request_submitted.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/check_if_voice_clone_request_submitted.rs index 6d9aef306d..a952160e10 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/check_if_voice_clone_request_submitted.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/check_if_voice_clone_request_submitted.rs @@ -10,6 +10,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::voice_clone_requests::get_voice_clone_request::{get_voice_clone_request_by_token, get_voice_clone_request_by_user_token}; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -29,41 +30,13 @@ pub struct CheckIfVoiceRequestSubmittedResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum CheckIfVoiceRequestSubmittedError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CheckIfVoiceRequestSubmittedError { - fn status_code(&self) -> StatusCode { - match *self { - CheckIfVoiceRequestSubmittedError::BadInput(_) => StatusCode::BAD_REQUEST, - CheckIfVoiceRequestSubmittedError::NotAuthorized => StatusCode::UNAUTHORIZED, - CheckIfVoiceRequestSubmittedError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for CheckIfVoiceRequestSubmittedError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn check_if_voice_clone_request_submitted_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -71,7 +44,7 @@ pub async fn check_if_voice_clone_request_submitted_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - CheckIfVoiceRequestSubmittedError::ServerError + CommonWebError::from_error(e) })?; let mut submitted_by_token = false; @@ -84,7 +57,7 @@ pub async fn check_if_voice_clone_request_submitted_handler( .await .map_err(|e| { warn!("Database error: {:?}", e); - CheckIfVoiceRequestSubmittedError::ServerError + CommonWebError::from_anyhow_error(e) })?; submitted_by_token = request.is_some(); @@ -97,7 +70,7 @@ pub async fn check_if_voice_clone_request_submitted_handler( .await .map_err(|e| { warn!("Database error: {:?}", e); - CheckIfVoiceRequestSubmittedError::ServerError + CommonWebError::from_anyhow_error(e) })?; submitted_by_user = request.is_some(); @@ -111,7 +84,7 @@ pub async fn check_if_voice_clone_request_submitted_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| CheckIfVoiceRequestSubmittedError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/create_voice_clone_request.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/create_voice_clone_request.rs index dbbcb7b52d..648076d9fe 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/create_voice_clone_request.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_clone_requests/create_voice_clone_request.rs @@ -11,6 +11,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::queries::voice_clone_requests::insert_voice_clone_requests_builder::InsertVoiceCloneRequestBuilder; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; // =============== Request =============== @@ -58,41 +59,13 @@ pub struct CreateVoiceRequestResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum CreateVoiceRequestError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CreateVoiceRequestError { - fn status_code(&self) -> StatusCode { - match *self { - CreateVoiceRequestError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateVoiceRequestError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateVoiceRequestError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for CreateVoiceRequestError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn create_voice_clone_request_handler( http_request: HttpRequest, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -100,7 +73,7 @@ pub async fn create_voice_clone_request_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - CreateVoiceRequestError::ServerError + CommonWebError::from_error(e) })?; let creator_ip_address = get_request_ip(&http_request); @@ -133,7 +106,7 @@ pub async fn create_voice_clone_request_handler( .await .map_err(|e| { warn!("creation error: {:?}", e); - CreateVoiceRequestError::ServerError + CommonWebError::from_anyhow_error(e) })?; let response = CreateVoiceRequestResponse { @@ -141,7 +114,7 @@ pub async fn create_voice_clone_request_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| CreateVoiceRequestError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/list_voice_conversion_models_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/list_voice_conversion_models_handler.rs index 79a48b9fe1..0b1ecc2fbd 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/list_voice_conversion_models_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/list_voice_conversion_models_handler.rs @@ -3,11 +3,8 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use std::fmt; use std::sync::Arc; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use lexical_sort::natural_lexical_cmp; @@ -16,13 +13,13 @@ use sqlx::pool::PoolConnection; use sqlx::MySql; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; +use crate::http_server::common_responses::common_web_error::CommonWebError; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; use migration::voice_conversion::list_vc_models_for_migration::list_vc_models_for_migration; use mysql_queries::queries::users::user_sessions::get_user_session_by_token::SessionUserRecord; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::state::server_state::ServerState; #[derive(Serialize, Clone)] @@ -67,38 +64,10 @@ pub struct ListVoiceConversionModelsSuccessResponse { pub success: bool, pub models: Vec, } - -#[derive(Debug)] -pub enum ListVoiceConversionModelsError { - ServerError, -} - -impl ResponseError for ListVoiceConversionModelsError { - fn status_code(&self) -> StatusCode { - match *self { - ListVoiceConversionModelsError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListVoiceConversionModelsError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListVoiceConversionModelsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - pub async fn list_voice_conversion_models_handler( http_request: HttpRequest, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { if server_state.flags.disable_voice_conversion_model_list_endpoint { // NB: Despite the cache being a powerful protector of the database (this is an expensive query), @@ -113,7 +82,7 @@ pub async fn list_voice_conversion_models_handler( let maybe_models = server_state.caches.ephemeral.voice_conversion_model_list.grab_copy_without_bump_if_unexpired() .map_err(|e| { error!("Error consulting cache: {:?}", e); - ListVoiceConversionModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; // NB: We don't know if we need a MySQL connection, so don't grab one unless we do. @@ -130,7 +99,7 @@ pub async fn list_voice_conversion_models_handler( .await .map_err(|e| { warn!("Could not acquire DB pool: {:?}", e); - ListVoiceConversionModelsError::ServerError + CommonWebError::from_error(e) })?; // TODO: Fail open in case the DB is down. Pull from expired cache if query fails. @@ -138,7 +107,7 @@ pub async fn list_voice_conversion_models_handler( .await .map_err(|e| { error!("Error querying database: {:?}", e); - ListVoiceConversionModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; maybe_mysql_connection = Some(mysql_connection); @@ -146,7 +115,7 @@ pub async fn list_voice_conversion_models_handler( server_state.caches.ephemeral.voice_conversion_model_list.store_copy(&models) .map_err(|e| { error!("Error storing cache: {:?}", e); - ListVoiceConversionModelsError::ServerError + CommonWebError::from_anyhow_error(e) })?; models @@ -166,7 +135,7 @@ pub async fn list_voice_conversion_models_handler( } }.map_err(|e| { warn!("Session checker error: {:?}", e); - ListVoiceConversionModelsError::ServerError + CommonWebError::from_error(e) })?; let maybe_session_user_token = maybe_user_session @@ -190,25 +159,25 @@ pub async fn list_voice_conversion_models_handler( }) } -pub fn render_response_busy(response: ListVoiceConversionModelsSuccessResponse) -> Result { +pub fn render_response_busy(response: ListVoiceConversionModelsSuccessResponse) -> Result { let body = render_response_payload(response)?; Ok(HttpResponse::TooManyRequests() .content_type("application/json") .body(body)) } -pub fn render_response_ok(response: ListVoiceConversionModelsSuccessResponse) -> Result { +pub fn render_response_ok(response: ListVoiceConversionModelsSuccessResponse) -> Result { let body = render_response_payload(response)?; Ok(HttpResponse::Ok() .content_type("application/json") .body(body)) } -pub fn render_response_payload(response: ListVoiceConversionModelsSuccessResponse) -> Result { +pub fn render_response_payload(response: ListVoiceConversionModelsSuccessResponse) -> Result { let body = serde_json::to_string(&response) .map_err(|e| { error!("error returning response: {:?}", e); - ListVoiceConversionModelsError::ServerError + CommonWebError::from_error(e) })?; Ok(body) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/delete_sample.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/delete_sample.rs index ce3e78f7e1..6cedc383ef 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/delete_sample.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/delete_sample.rs @@ -12,6 +12,7 @@ use mysql_queries::queries::voice_designer::voice_samples::get_dataset_sample::g use tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::util::delete_role_disambiguation::{delete_role_disambiguation, DeleteRole}; // TODO(bt,2023-10-10): This is way too much boilerplate. @@ -28,49 +29,13 @@ pub struct DeleteSampleRequest { /// NB: this is only to disambiguate when a user is both a mod and an author. as_mod: Option, } - -#[derive(Debug)] -pub enum DeleteSampleError { - BadInput(String), - NotAuthorized, - NotFound, - ServerError, -} - -impl ResponseError for DeleteSampleError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteSampleError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteSampleError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteSampleError::NotFound => StatusCode::NOT_FOUND, - DeleteSampleError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - DeleteSampleError::BadInput(reason) => reason.to_string(), - DeleteSampleError::NotAuthorized => "unauthorized".to_string(), - DeleteSampleError::NotFound => "not found".to_string(), - DeleteSampleError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl std::fmt::Display for DeleteSampleError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} pub async fn delete_sample_handler( http_request: HttpRequest, path: Path, request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -78,14 +43,14 @@ pub async fn delete_sample_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteSampleError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteSampleError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -102,9 +67,9 @@ pub async fn delete_sample_handler( let dataset_sample = match inference_result_query_result { Err(e) => { warn!("query error: {:?}", e); - return Err(DeleteSampleError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } - Ok(None) => return Err(DeleteSampleError::NotFound), + Ok(None) => return Err(CommonWebError::NotFound), Ok(Some(sample)) => sample, }; @@ -118,7 +83,7 @@ pub async fn delete_sample_handler( if !is_author && !is_mod { warn!("user is not allowed to delete samples: {:?}", user_session.user_token); - return Err(DeleteSampleError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let delete_role = delete_role_disambiguation(is_mod, is_author, request.as_mod); @@ -126,7 +91,7 @@ pub async fn delete_sample_handler( let query_result = if request.set_delete { match delete_role { DeleteRole::ErrorDoNotDelete => { - return Err(DeleteSampleError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { delete_sample_as_user(&path.sample_token, &server_state.mysql_pool).await @@ -138,7 +103,7 @@ pub async fn delete_sample_handler( } else { match delete_role { DeleteRole::ErrorDoNotDelete => { - return Err(DeleteSampleError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { undelete_sample_as_user(&path.sample_token, &server_state.mysql_pool).await @@ -153,7 +118,7 @@ pub async fn delete_sample_handler( Ok(_) => {}, Err(err) => { warn!("Delete DB error: {:?}", err); - return Err(DeleteSampleError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs index 05433ed4e8..c34747aa0b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs @@ -14,6 +14,7 @@ use tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken; use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; #[derive(Serialize, Clone)] pub struct ZsSampleRecordForResponse { @@ -42,46 +43,24 @@ pub struct ListSamplesByDatasetSuccessResponse { pub struct ListSamplesByDatasetPathInfo { dataset_token: String, } - -#[derive(Debug)] -pub enum ListSamplesByDatasetError { - NotAuthorized, - ServerError, -} - -impl std::fmt::Display for ListSamplesByDatasetError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for ListSamplesByDatasetError { - fn status_code(&self) -> StatusCode { - match *self { - ListSamplesByDatasetError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListSamplesByDatasetError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - pub async fn list_samples_by_dataset_handler( http_request: HttpRequest, path: web::Path, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state.session_checker.maybe_get_user_session( &http_request, &server_state.mysql_pool ).await.map_err(|e| { warn!("Session checker error: {:?}", e); - ListSamplesByDatasetError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(ListSamplesByDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); }, }; @@ -98,14 +77,14 @@ pub async fn list_samples_by_dataset_handler( &server_state.mysql_pool ).await.map_err(|e| { warn!("list_samples error: {:?}", e); - ListSamplesByDatasetError::ServerError + CommonWebError::from_anyhow_error(e) }); let samples = match query_results { Ok(samples) => samples, Err(e) => { warn!("list_samples error: {:?}", e); - return Err(ListSamplesByDatasetError::ServerError); + return Err(CommonWebError::from_error(e)); }, }; @@ -131,7 +110,7 @@ pub async fn list_samples_by_dataset_handler( let body = serde_json::to_string(&response).map_err(|e| { warn!("json serialization error: {:?}", e); - ListSamplesByDatasetError::ServerError + CommonWebError::from_error(e) })?; Ok(HttpResponse::Ok().content_type("application/json").body(body)) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/create_dataset.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/create_dataset.rs index ee85a82bf7..33c5afbc61 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/create_dataset.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/create_dataset.rs @@ -13,6 +13,7 @@ use mysql_queries::queries::voice_designer::datasets::create_dataset::{create_da use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; #[derive(Deserialize)] pub struct CreateDatasetRequest { @@ -30,52 +31,24 @@ pub struct CreateDatasetResponse { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum CreateDatasetError { - BadInput(String), - NotAuthorized, - ServerError, -} - -impl ResponseError for CreateDatasetError { - fn status_code(&self) -> StatusCode { - match *self { - CreateDatasetError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateDatasetError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateDatasetError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using DeriveMore since Clion doesn't understand it. -impl fmt::Display for CreateDatasetError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== -pub async fn create_dataset_handler(http_request: HttpRequest, request: web::Json, server_state: web::Data>) -> Result { +pub async fn create_dataset_handler(http_request: HttpRequest, request: web::Json, server_state: web::Data>) -> Result { let maybe_user_session = server_state.session_checker.maybe_get_user_session(&http_request, &server_state.mysql_pool).await.map_err(|e| { error!("Error getting user session: {:?}", e); - CreateDatasetError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(CreateDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); }, }; - let idempotency_token = request.idempotency_token.clone().ok_or(CreateDatasetError::BadInput("no idempotency token provided".to_string()))?; + let idempotency_token = request.idempotency_token.clone().ok_or(CommonWebError::BadInputWithSimpleMessage("no idempotency token provided".to_string()))?; let title = request.title.clone(); @@ -95,7 +68,7 @@ pub async fn create_dataset_handler(http_request: HttpRequest, request: web::Jso Ok(token) => token, Err(e) => { error!("Error creating dataset: {:?}", e); - return Err(CreateDatasetError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -106,7 +79,7 @@ pub async fn create_dataset_handler(http_request: HttpRequest, request: web::Jso let body = serde_json::to_string(&response) - .map_err(|e| CreateDatasetError::ServerError)?; + .map_err(|e| CommonWebError::from_error(e))?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/delete_dataset.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/delete_dataset.rs index 20f1ef279d..02680799f6 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/delete_dataset.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/delete_dataset.rs @@ -13,6 +13,7 @@ use mysql_queries::queries::voice_designer::datasets::get_dataset::get_dataset_b use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; use crate::http_server::web_utils::response_success_helpers::simple_json_success; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use crate::util::delete_role_disambiguation::{delete_role_disambiguation, DeleteRole}; @@ -30,37 +31,7 @@ pub struct DeleteDatasetPathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum DeleteDatasetError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for DeleteDatasetError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteDatasetError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteDatasetError::NotFound => StatusCode::NOT_FOUND, - DeleteDatasetError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteDatasetError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteDatasetError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn delete_dataset_handler( @@ -68,21 +39,21 @@ pub async fn delete_dataset_handler( path: Path, request: web::Json, server_state: web::Data> -) -> Result{ +) -> Result{ let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteDatasetError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -99,11 +70,11 @@ pub async fn delete_dataset_handler( Ok(Some(dataset)) => dataset, Ok(None) => { warn!("Dataset not found: {:?}", dataset_token); - return Err(DeleteDatasetError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up dataset: {:?}", err); - return Err(DeleteDatasetError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -113,7 +84,7 @@ pub async fn delete_dataset_handler( if !is_creator && !is_mod { warn!("user is not allowed to delete this dataset: {:?}", user_session.user_token); - return Err(DeleteDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let delete_role = delete_role_disambiguation(is_mod, is_creator, request.as_mod); @@ -122,7 +93,7 @@ pub async fn delete_dataset_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to delete datasets: {:?}", user_session.user_token); - return Err(DeleteDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { delete_dataset_as_user( @@ -142,7 +113,7 @@ pub async fn delete_dataset_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to undelete voices: {:?}", user_session.user_token); - return Err(DeleteDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { // NB: Technically only mods can see their own datasets @@ -165,7 +136,7 @@ pub async fn delete_dataset_handler( Ok(_) => {}, Err(err) => { warn!("Update dataset mod approval status DB error: {:?}", err); - return Err(DeleteDatasetError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/get_dataset.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/get_dataset.rs index da4f538ec2..216eb7c368 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/get_dataset.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/get_dataset.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use log::warn; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; +use crate::http_server::common_responses::common_web_error::CommonWebError; use enums::common::visibility::Visibility; use mysql_queries::queries::voice_designer::datasets::get_dataset::get_dataset_by_token; use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; @@ -37,35 +38,11 @@ pub struct GetDatasetResponse { pub struct GetDatasetPathInfo { dataset_token: String, } - -#[derive(Debug)] -pub enum GetDatasetError { - NotAuthorized, - NotFound, - ServerError, -} - -impl fmt::Display for GetDatasetError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for GetDatasetError { - fn status_code(&self) -> StatusCode { - match *self { - GetDatasetError::NotAuthorized => StatusCode::UNAUTHORIZED, - GetDatasetError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetDatasetError::NotFound => StatusCode::NOT_FOUND, - } - } -} - pub async fn get_dataset_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -73,14 +50,14 @@ pub async fn get_dataset_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetDatasetError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(GetDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -98,11 +75,11 @@ pub async fn get_dataset_handler( Ok(Some(dataset)) => dataset, Ok(None) => { warn!("Dataset not found: {:?}", dataset_token); - return Err(GetDatasetError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up dataset: {:?}", err); - return Err(GetDatasetError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -112,7 +89,7 @@ pub async fn get_dataset_handler( if !is_creator && !is_mod { warn!("user is not allowed to view this dataset: {:?}", user_session.user_token); - return Err(GetDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let response = GetDatasetResponse { @@ -133,7 +110,7 @@ pub async fn get_dataset_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetDatasetError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/update_dataset.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/update_dataset.rs index fe9b0d2deb..37a437fb80 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/update_dataset.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_datasets/update_dataset.rs @@ -16,6 +16,7 @@ use mysql_queries::queries::voice_designer::datasets::update_dataset::{update_da use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; use crate::configs::supported_languages_for_models::get_canonicalized_language_tag_for_model; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Deserialize)] @@ -41,44 +42,14 @@ pub struct UpdateDatasetPathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum UpdateDatasetError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for UpdateDatasetError { - fn status_code(&self) -> StatusCode { - match *self { - UpdateDatasetError::BadInput(_) => StatusCode::BAD_REQUEST, - UpdateDatasetError::NotFound => StatusCode::NOT_FOUND, - UpdateDatasetError::NotAuthorized => StatusCode::UNAUTHORIZED, - UpdateDatasetError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for UpdateDatasetError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn update_dataset_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -86,14 +57,14 @@ pub async fn update_dataset_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - UpdateDatasetError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(UpdateDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -110,11 +81,11 @@ pub async fn update_dataset_handler( Ok(Some(dataset)) => dataset, Ok(None) => { warn!("Dataset not found: {:?}", dataset_token); - return Err(UpdateDatasetError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up dataset: {:?}", err); - return Err(UpdateDatasetError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -125,7 +96,7 @@ pub async fn update_dataset_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this dataset: {:?}", user_session.user_token); - return Err(UpdateDatasetError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut title = None; @@ -135,7 +106,7 @@ pub async fn update_dataset_handler( if let Some(payload) = request.title.as_deref() { if user_input_common::check_for_slurs::contains_slurs(payload) { - return Err(UpdateDatasetError::BadInput("title contains slurs".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("title contains slurs".to_string())); } title = Some(payload.trim().to_string()); @@ -153,7 +124,7 @@ pub async fn update_dataset_handler( .transpose() .map_err(|e| { error!("Error parsing language tag '{}': {:?}", tag, e); - UpdateDatasetError::BadInput("bad locale string".to_string()) + CommonWebError::BadInputWithSimpleMessage("bad locale string".to_string()) })?; if let Some(full_tag) = maybe_full_canonical_tag { @@ -166,7 +137,7 @@ pub async fn update_dataset_handler( if let Some(visibility) = request.creator_set_visibility.as_deref() { creator_set_visibility = Visibility::from_str(visibility) - .map_err(|_| UpdateDatasetError::BadInput("bad record visibility".to_string()))?; + .map_err(|_| CommonWebError::BadInputWithSimpleMessage("bad record visibility".to_string()))?; } @@ -194,7 +165,7 @@ pub async fn update_dataset_handler( Ok(_) => {}, Err(err) => { warn!("Update Dataset DB error: {:?}", err); - return Err(UpdateDatasetError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/delete_voice.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/delete_voice.rs index 2711e05e4c..dbcc9f3256 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/delete_voice.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/delete_voice.rs @@ -13,6 +13,7 @@ use mysql_queries::queries::voice_designer::voices::get_voice::get_voice_by_toke use tokens::tokens::zs_voices::ZsVoiceToken; use crate::http_server::web_utils::response_success_helpers::simple_json_success; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use crate::util::delete_role_disambiguation::{delete_role_disambiguation, DeleteRole}; @@ -30,37 +31,7 @@ pub struct DeleteVoicePathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum DeleteVoiceError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for DeleteVoiceError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteVoiceError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteVoiceError::NotFound => StatusCode::NOT_FOUND, - DeleteVoiceError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteVoiceError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteVoiceError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn delete_voice_handler( @@ -68,21 +39,21 @@ pub async fn delete_voice_handler( path: Path, request: web::Json, server_state: web::Data> -) -> Result{ +) -> Result{ let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteVoiceError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -99,11 +70,11 @@ pub async fn delete_voice_handler( Ok(Some(voice)) => voice, Ok(None) => { warn!("Voice not found: {:?}", voice_token); - return Err(DeleteVoiceError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up voice: {:?}", err); - return Err(DeleteVoiceError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -113,7 +84,7 @@ pub async fn delete_voice_handler( if !is_creator && !is_mod { warn!("user is not allowed to delete this voice: {:?}", user_session.user_token); - return Err(DeleteVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let delete_role = delete_role_disambiguation(is_mod, is_creator, request.as_mod); @@ -122,7 +93,7 @@ pub async fn delete_voice_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to delete voices: {:?}", user_session.user_token); - return Err(DeleteVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { delete_voice_as_user( @@ -142,7 +113,7 @@ pub async fn delete_voice_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to undelete voices: {:?}", user_session.user_token); - return Err(DeleteVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { undelete_voice_as_user( @@ -164,7 +135,7 @@ pub async fn delete_voice_handler( Ok(_) => {}, Err(err) => { warn!("Update voice mod approval status DB error: {:?}", err); - return Err(DeleteVoiceError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/get_voice.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/get_voice.rs index 470ea18f3c..1136685112 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/get_voice.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/get_voice.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use log::warn; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; +use crate::http_server::common_responses::common_web_error::CommonWebError; use enums::common::visibility::Visibility; use mysql_queries::queries::voice_designer::voices::get_voice::get_voice_by_token; use tokens::tokens::zs_voices::ZsVoiceToken; @@ -37,35 +38,11 @@ pub struct GetVoiceResponse { pub struct GetVoicePathInfo { voice_token: String, } - -#[derive(Debug)] -pub enum GetVoiceError { - NotAuthorized, - NotFound, - ServerError, -} - -impl fmt::Display for GetVoiceError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for GetVoiceError { - fn status_code(&self) -> StatusCode { - match *self { - GetVoiceError::NotAuthorized => StatusCode::UNAUTHORIZED, - GetVoiceError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetVoiceError::NotFound => StatusCode::NOT_FOUND, - } - } -} - pub async fn get_voice_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -73,14 +50,14 @@ pub async fn get_voice_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetVoiceError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(GetVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -98,11 +75,11 @@ pub async fn get_voice_handler( Ok(Some(voice)) => voice, Ok(None) => { warn!("Voice not found: {:?}", voice_token); - return Err(GetVoiceError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up voice: {:?}", err); - return Err(GetVoiceError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -112,7 +89,7 @@ pub async fn get_voice_handler( if !is_creator && !is_mod { warn!("user is not allowed to view this voice: {:?}", user_session.user_token); - return Err(GetVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let response = GetVoiceResponse { @@ -133,7 +110,7 @@ pub async fn get_voice_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetVoiceError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/list_available_voices.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/list_available_voices.rs index 0ec6e14ba5..68456e37fc 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/list_available_voices.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/list_available_voices.rs @@ -7,6 +7,7 @@ use chrono::{DateTime, Utc}; use log::{info, warn}; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; +use crate::http_server::common_responses::common_web_error::CommonWebError; use enums::common::visibility::Visibility; use mysql_queries::queries::voice_designer::voices::list_voices_query_builder::ListVoicesQueryBuilder; use tokens::tokens::zs_voices::ZsVoiceToken; @@ -43,40 +44,18 @@ pub struct ZsVoiceForList { pub created_at: DateTime, pub updated_at: DateTime, } - -#[derive(Debug)] -pub enum ListZsVoicesError { - NotAuthorized, - ServerError, -} - -impl std::fmt::Display for ListZsVoicesError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for ListZsVoicesError { - fn status_code(&self) -> StatusCode { - match *self { - ListZsVoicesError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListZsVoicesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - pub async fn list_available_voices_handler( http_request: HttpRequest, query: web::Query, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state.session_checker.maybe_get_user_session( &http_request, &server_state.mysql_pool ).await.map_err(|e| { warn!("Session checker error: {:?}", e); - ListZsVoicesError::ServerError + CommonWebError::from_error(e) })?; let mut is_mod = false; @@ -87,7 +66,7 @@ pub async fn list_available_voices_handler( } None => { info!("not logged in"); - return Err(ListZsVoicesError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -101,7 +80,7 @@ pub async fn list_available_voices_handler( let cursor = server_state.sort_key_crypto.decrypt_id(cursor) .map_err(|e| { warn!("crypto error: {:?}", e); - ListZsVoicesError::ServerError + CommonWebError::from_anyhow_error(e) })?; Some(cursor) } else { @@ -130,7 +109,7 @@ pub async fn list_available_voices_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListZsVoicesError::ServerError); + return Err(CommonWebError::from_anyhow_error(e)); } }; @@ -138,7 +117,7 @@ pub async fn list_available_voices_handler( let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) .map_err(|e| { warn!("crypto error: {:?}", e); - ListZsVoicesError::ServerError + CommonWebError::from_anyhow_error(e) })?; Some(cursor) } else { @@ -149,7 +128,7 @@ pub async fn list_available_voices_handler( let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) .map_err(|e| { warn!("crypto error: {:?}", e); - ListZsVoicesError::ServerError + CommonWebError::from_anyhow_error(e) })?; Some(cursor) } else { @@ -180,7 +159,7 @@ pub async fn list_available_voices_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ListZsVoicesError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/update_voice.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/update_voice.rs index 80c74dab5e..513df6d9d4 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/update_voice.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/update_voice.rs @@ -15,6 +15,7 @@ use mysql_queries::queries::voice_designer::voices::update_voice::{update_voice, use tokens::tokens::zs_voices::ZsVoiceToken; use crate::configs::supported_languages_for_models::get_canonicalized_language_tag_for_model; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; #[derive(Deserialize)] @@ -40,44 +41,14 @@ pub struct UpdateVoicePathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize)] -pub enum UpdateVoiceError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for UpdateVoiceError { - fn status_code(&self) -> StatusCode { - match *self { - UpdateVoiceError::BadInput(_) => StatusCode::BAD_REQUEST, - UpdateVoiceError::NotFound => StatusCode::NOT_FOUND, - UpdateVoiceError::NotAuthorized => StatusCode::UNAUTHORIZED, - UpdateVoiceError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for UpdateVoiceError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== pub async fn update_voice_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -85,14 +56,14 @@ pub async fn update_voice_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - UpdateVoiceError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(UpdateVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -109,11 +80,11 @@ pub async fn update_voice_handler( Ok(Some(voice)) => voice, Ok(None) => { warn!("Voice not found: {:?}", voice_token); - return Err(UpdateVoiceError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up voice: {:?}", err); - return Err(UpdateVoiceError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -124,7 +95,7 @@ pub async fn update_voice_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this voice: {:?}", user_session.user_token); - return Err(UpdateVoiceError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut title = None; @@ -134,7 +105,7 @@ pub async fn update_voice_handler( if let Some(payload) = request.title.as_deref() { if user_input_common::check_for_slurs::contains_slurs(payload) { - return Err(UpdateVoiceError::BadInput("title contains slurs".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("title contains slurs".to_string())); } title = Some(payload.trim().to_string()); @@ -152,7 +123,7 @@ pub async fn update_voice_handler( .transpose() .map_err(|e| { error!("Error parsing language tag '{}': {:?}", tag, e); - UpdateVoiceError::BadInput("bad locale string".to_string()) + CommonWebError::BadInputWithSimpleMessage("bad locale string".to_string()) })?; if let Some(full_tag) = maybe_full_canonical_tag { @@ -165,7 +136,7 @@ pub async fn update_voice_handler( if let Some(visibility) = request.creator_set_visibility.as_deref() { creator_set_visibility = Visibility::from_str(visibility) - .map_err(|_| UpdateVoiceError::BadInput("bad record visibility".to_string()))?; + .map_err(|_| CommonWebError::BadInputWithSimpleMessage("bad record visibility".to_string()))?; } @@ -191,7 +162,7 @@ pub async fn update_voice_handler( Ok(_) => {}, Err(err) => { warn!("Update Voice DB error: {:?}", err); - return Err(UpdateVoiceError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/delete/delete_weight_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/delete/delete_weight_handler.rs index ce13550727..af62499971 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/delete/delete_weight_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/delete/delete_weight_handler.rs @@ -19,6 +19,7 @@ use tokens::tokens::model_weights::ModelWeightToken; use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess; use crate::http_server::web_utils::response_success_helpers::simple_json_success; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::state::server_state::ServerState; use crate::util::delete_role_disambiguation::{delete_role_disambiguation, DeleteRole}; @@ -35,47 +36,16 @@ pub struct DeleteWeightRequest { // =============== Error Response =============== - -#[derive(Debug, Serialize,ToSchema)] -pub enum DeleteWeightError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for DeleteWeightError { - fn status_code(&self) -> StatusCode { - match *self { - DeleteWeightError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteWeightError::NotFound => StatusCode::NOT_FOUND, - DeleteWeightError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteWeightError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteWeightError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - - #[utoipa::path( delete, tag = "Model Weights", path = "/v1/weights/weight/{weight_token}", responses( (status = 200, description = "Success Delete", body = SimpleGenericJsonSuccess), - (status = 400, description = "Bad input", body = DeleteWeightError), - (status = 401, description = "Not authorized", body = DeleteWeightError), - (status = 500, description = "Server error", body = DeleteWeightError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = DeleteWeightRequest, description = "Payload for Request"), @@ -87,21 +57,21 @@ pub async fn delete_weight_handler( path: Path, request: web::Json, server_state: web::Data> - ) -> Result{ + ) -> Result{ let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteWeightError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(DeleteWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -118,11 +88,11 @@ pub async fn delete_weight_handler( Ok(Some(weight)) => weight, Ok(None) => { warn!("Weight not found: {:?}", weight_token); - return Err(DeleteWeightError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up weight: {:?}", err); - return Err(DeleteWeightError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -132,7 +102,7 @@ pub async fn delete_weight_handler( if !is_creator && !is_mod { warn!("user is not allowed to delete this weight: {:?}", user_session.user_token); - return Err(DeleteWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let delete_role = delete_role_disambiguation(is_mod, is_creator, Some(request.as_mod)); @@ -141,7 +111,7 @@ pub async fn delete_weight_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to delete weights: {:?}", user_session.user_token); - return Err(DeleteWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { delete_weights_as_user( @@ -160,7 +130,7 @@ pub async fn delete_weight_handler( match delete_role { DeleteRole::ErrorDoNotDelete => { warn!("user is not allowed to undelete weights: {:?}", user_session.user_token); - return Err(DeleteWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } DeleteRole::AsUser => { undelete_weights_as_user( @@ -181,7 +151,7 @@ pub async fn delete_weight_handler( Ok(_) => {}, Err(err) => { warn!("Update weight mod approval status DB error: {:?}", err); - return Err(DeleteWeightError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get/get_weight_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get/get_weight_handler.rs index 684ff35999..5013c38322 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get/get_weight_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get/get_weight_handler.rs @@ -18,6 +18,7 @@ use primitives::numerics::u64_to_u32_saturating::u64_to_u32_saturating; use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::common_responses::media::weights_cover_image_details::WeightsCoverImageDetails; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain; @@ -86,38 +87,15 @@ pub struct GetWeightResponse { pub struct GetWeightPathInfo { weight_token: ModelWeightToken, } - -#[derive(Debug, ToSchema)] -pub enum GetWeightError { - NotAuthorized, - NotFound, - ServerError, -} - -impl fmt::Display for GetWeightError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for GetWeightError { - fn status_code(&self) -> StatusCode { - match *self { - GetWeightError::NotAuthorized => StatusCode::UNAUTHORIZED, - GetWeightError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - GetWeightError::NotFound => StatusCode::NOT_FOUND, - } - } -} #[utoipa::path( get, tag = "Model Weights", path = "/v1/weights/weight/{weight_token}", responses( (status = 200, description = "Success Update", body = GetWeightResponse), - (status = 400, description = "Bad input", body = GetWeightError), - (status = 401, description = "Not authorized", body = GetWeightError), - (status = 500, description = "Server error", body = GetWeightError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("path" = GetWeightPathInfo, description = "Path for Request") @@ -127,14 +105,14 @@ pub async fn get_weight_handler( http_request: HttpRequest, path: Path, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - GetWeightError::ServerError + CommonWebError::from_error(e) })?; let is_mod = maybe_user_session @@ -152,11 +130,11 @@ pub async fn get_weight_handler( Ok(Some(weight)) => weight, Ok(None) => { warn!("Weight not found: {:?}", &path.weight_token); - return Err(GetWeightError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up weight: {:?}", err); - return Err(GetWeightError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -168,7 +146,7 @@ pub async fn get_weight_handler( Some(session) => session, None => { warn!("not logged in"); - return Err(GetWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -176,7 +154,7 @@ pub async fn get_weight_handler( if !is_mod && session_user_token.as_str() != user_session.user_token.as_str() { warn!("user is not allowed to view this weight: {:?}", user_session.user_token.as_str()); - return Err(GetWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } } @@ -239,7 +217,7 @@ pub async fn get_weight_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| GetWeightError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list/list_weights_by_user_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list/list_weights_by_user_handler.rs index 7e1335bfa0..528eeaf11d 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list/list_weights_by_user_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list/list_weights_by_user_handler.rs @@ -19,6 +19,7 @@ use primitives::numerics::u64_to_u32_saturating::u64_to_u32_saturating; use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::common_responses::media::weights_cover_image_details::WeightsCoverImageDetails; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::pagination_page::PaginationPage; use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; @@ -104,36 +105,14 @@ pub struct ListWeightsForUserQueryParams { pub struct ListWeightsByUserPathInfo { username: String, } - -#[derive(Debug,ToSchema)] -pub enum ListWeightsByUserError { - NotAuthorized, - ServerError, -} - -impl fmt::Display for ListWeightsByUserError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl ResponseError for ListWeightsByUserError { - fn status_code(&self) -> StatusCode { - match *self { - ListWeightsByUserError::NotAuthorized => StatusCode::UNAUTHORIZED, - ListWeightsByUserError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } -} - #[utoipa::path( get, tag = "Model Weights", path = "/v1/weights/by_user/{username}", responses( (status = 200, description = "List Weights by user", body = ListWeightsByUserSuccessResponse), - (status = 401, description = "Not authorized", body = ListWeightsByUserError), - (status = 500, description = "Server error", body = ListWeightsByUserError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("path" = ListWeightsByUserPathInfo, description = "Payload for Request"), @@ -145,7 +124,7 @@ pub async fn list_weights_by_user_handler( path: Path, query: Query, server_state: web::Data> -) -> Result { +) -> Result { let maybe_user_session = server_state .session_checker @@ -153,7 +132,7 @@ pub async fn list_weights_by_user_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListWeightsByUserError::ServerError + CommonWebError::from_error(e) })?; let mut is_author = false; @@ -195,14 +174,14 @@ pub async fn list_weights_by_user_handler( } ).await.map_err(|e| { warn!("Error querying for weights: {:?}", e); - ListWeightsByUserError::ServerError + CommonWebError::from_anyhow_error(e) }); let results_page = match query_results { Ok(results) => results, Err(e) => { warn!("Error querying for weights: {:?}", e); - return Err(ListWeightsByUserError::ServerError); + return Err(CommonWebError::from_error(e)); } }; @@ -270,7 +249,7 @@ pub async fn list_weights_by_user_handler( let body = serde_json::to_string(&response) - .map_err(|e| ListWeightsByUserError::ServerError)?; + .map_err(CommonWebError::from_error)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/set_model_weight_cover_image_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/set_model_weight_cover_image_handler.rs index 3bedd57694..99d410c59e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/set_model_weight_cover_image_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/set_model_weight_cover_image_handler.rs @@ -19,6 +19,7 @@ use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::model_weights::ModelWeightToken; use crate::state::server_state::ServerState; +use crate::http_server::common_responses::common_web_error::CommonWebError; #[derive(Deserialize, ToSchema)] pub struct SetModelWeightCoverImageRequest { @@ -37,37 +38,7 @@ pub struct SetModelWeightCoverImagePathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum SetModelWeightCoverImageError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for SetModelWeightCoverImageError { - fn status_code(&self) -> StatusCode { - match *self { - SetModelWeightCoverImageError::BadInput(_) => StatusCode::BAD_REQUEST, - SetModelWeightCoverImageError::NotFound => StatusCode::NOT_FOUND, - SetModelWeightCoverImageError::NotAuthorized => StatusCode::UNAUTHORIZED, - SetModelWeightCoverImageError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for SetModelWeightCoverImageError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== #[utoipa::path( @@ -76,9 +47,9 @@ impl fmt::Display for SetModelWeightCoverImageError { path = "/v1/weights/weight/{weight_token}/cover_image", responses( (status = 200, description = "Success Update", body = SetModelWeightCoverImageResponse), - (status = 400, description = "Bad input", body = SetModelWeightCoverImageError), - (status = 401, description = "Not authorized", body = SetModelWeightCoverImageError), - (status = 500, description = "Server error", body = SetModelWeightCoverImageError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = SetModelWeightCoverImageRequest, description = "Payload for Request"), @@ -89,7 +60,7 @@ pub async fn set_model_weight_cover_image_handler( http_request: HttpRequest, path: Path, request: web::Json, - server_state: web::Data>) -> Result + server_state: web::Data>) -> Result { let maybe_user_session = server_state .session_checker @@ -97,14 +68,14 @@ pub async fn set_model_weight_cover_image_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - SetModelWeightCoverImageError::ServerError + CommonWebError::from_error(e) })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(SetModelWeightCoverImageError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } }; @@ -122,11 +93,11 @@ pub async fn set_model_weight_cover_image_handler( Ok(Some(model_weight)) => model_weight, Ok(None) => { warn!("Model weight not found: {:?}", &path.token); - return Err(SetModelWeightCoverImageError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up model_weights : {:?}", err); - return Err(SetModelWeightCoverImageError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -134,7 +105,7 @@ pub async fn set_model_weight_cover_image_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this media_file: {:?}", user_session.user_token); - return Err(SetModelWeightCoverImageError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut maybe_set_media_file_token = None; @@ -156,11 +127,11 @@ pub async fn set_model_weight_cover_image_handler( Ok(Some(media_file)) => media_file, Ok(None) => { warn!("Media file not found: {:?}", media_file_token); - return Err(SetModelWeightCoverImageError::NotFound); + return Err(CommonWebError::NotFound); }, Err(err) => { warn!("Error looking up model_weights : {:?}", err); - return Err(SetModelWeightCoverImageError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -170,7 +141,7 @@ pub async fn set_model_weight_cover_image_handler( let can_use_image = media_file.media_type == MediaFileType::Image; if !can_use_image { - return Err(SetModelWeightCoverImageError::BadInput("Invalid media file token.".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("Invalid media file token.".to_string())); } maybe_set_media_file_token = Some(media_file.token); @@ -190,7 +161,7 @@ pub async fn set_model_weight_cover_image_handler( Ok(_) => {}, Err(err) => { warn!("Update MediaFile DB error: {:?}", err); - return Err(SetModelWeightCoverImageError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs index 1f3e4b3e91..9601823e71 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs @@ -10,6 +10,7 @@ use sqlx::MySqlPool; use utoipa::ToSchema; use crate::configs::supported_languages_for_models::{get_canonicalized_language_tag_for_model, get_primary_language_subtag}; +use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::web_utils::user_session::require_user_session::RequireUserSessionError; use crate::http_server::web_utils::user_session::require_user_session_extended_using_connection::require_user_session_extended_using_connection; use crate::state::server_state::ServerState; @@ -60,37 +61,7 @@ pub struct UpdateWeightPathInfo { } // =============== Error Response =============== - -#[derive(Debug, Serialize, ToSchema)] -pub enum UpdateWeightError { - BadInput(String), - NotFound, - NotAuthorized, - ServerError, -} - -impl ResponseError for UpdateWeightError { - fn status_code(&self) -> StatusCode { - match *self { - UpdateWeightError::BadInput(_) => StatusCode::BAD_REQUEST, - UpdateWeightError::NotFound => StatusCode::NOT_FOUND, - UpdateWeightError::NotAuthorized => StatusCode::UNAUTHORIZED, - UpdateWeightError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for UpdateWeightError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - // =============== Handler =============== /// Handle updates to model weight metadata (using sparse field updates!) @@ -100,9 +71,9 @@ impl fmt::Display for UpdateWeightError { path = "/v1/weights/weight/{weight_token}", responses( (status = 200, description = "Success Update", body = SimpleGenericJsonSuccess), - (status = 400, description = "Bad input", body = UpdateWeightError), - (status = 401, description = "Not authorized", body = UpdateWeightError), - (status = 500, description = "Server error", body = UpdateWeightError), + (status = 400, description = "Bad input", body = CommonWebError), + (status = 401, description = "Not authorized", body = CommonWebError), + (status = 500, description = "Server error", body = CommonWebError), ), params( ("request" = UpdateWeightRequest, description = "Payload for Request"), @@ -115,13 +86,13 @@ pub async fn update_weight_handler( request: web::Json, mysql_pool: web::Data, server_state: web::Data> -) -> Result { +) -> Result { let mut mysql_connection = mysql_pool .acquire() .await .map_err(|err| { warn!("could not acquire mysql connection: {:?}", err); - UpdateWeightError::ServerError + CommonWebError::from_error(err) })?; let user_session = require_user_session_extended_using_connection( @@ -130,10 +101,10 @@ pub async fn update_weight_handler( &mut mysql_connection) .await .map_err(|err| match err { - RequireUserSessionError::NotAuthorized => UpdateWeightError::NotAuthorized, + RequireUserSessionError::NotAuthorized => CommonWebError::NotAuthorized, _ => { warn!("get user session error: {:?}", err); - UpdateWeightError::ServerError + CommonWebError::from_error(err) }, })?; @@ -152,11 +123,11 @@ pub async fn update_weight_handler( Ok(Some(weight)) => weight, Ok(None) => { warn!("Weight not found: {:?}", weight_token); - return Err(UpdateWeightError::NotFound); + return Err(CommonWebError::NotFound); } Err(err) => { warn!("Error looking up weight: {:?}", err); - return Err(UpdateWeightError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }; @@ -166,7 +137,7 @@ pub async fn update_weight_handler( if !is_creator && !is_mod { warn!("user is not allowed to edit this weight: {:?}", user_session.user_token); - return Err(UpdateWeightError::NotAuthorized); + return Err(CommonWebError::NotAuthorized); } let mut weight_title = None; @@ -178,7 +149,7 @@ pub async fn update_weight_handler( if let Some(title) = &request.title { if contains_slurs(title) { - return Err(UpdateWeightError::BadInput("Title contains slurs".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("Title contains slurs".to_string())); } weight_title = Some(title.trim().to_string()); } @@ -193,22 +164,22 @@ pub async fn update_weight_handler( &server_state.mysql_pool ).await.map_err(|err| { warn!("Error looking up media file: {:?}", err); - UpdateWeightError::ServerError + CommonWebError::from_anyhow_error(err) })?; let maybe_media_file_type = maybe_media_file.map(|media_file| media_file.media_type); match maybe_media_file_type { Some(MediaFileType::Image) => cover_image = Some(CoverImageOption::SetCoverImage(media_file_token)), - None => return Err(UpdateWeightError::BadInput("Media file does not exist".to_string())), - _ => return Err(UpdateWeightError::BadInput("Media file is the wrong type".to_string())), + None => return Err(CommonWebError::BadInputWithSimpleMessage("Media file does not exist".to_string())), + _ => return Err(CommonWebError::BadInputWithSimpleMessage("Media file is the wrong type".to_string())), } } } if let Some(markdown) = &request.description_markdown { if contains_slurs(markdown) { - return Err(UpdateWeightError::BadInput("Description contains slurs".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("Description contains slurs".to_string())); } let markdown = markdown.trim().to_string(); let html = simple_markdown_to_html(&markdown); @@ -226,7 +197,7 @@ pub async fn update_weight_handler( WeightsType::HifiganTacotron2 => {} WeightsType::VallE => {} _ => { - return Err(UpdateWeightError::BadInput("Language tag is not applicable to this model type".to_string())); + return Err(CommonWebError::BadInputWithSimpleMessage("Language tag is not applicable to this model type".to_string())); } } } @@ -256,7 +227,7 @@ pub async fn update_weight_handler( Ok(()) => {} Err(err) => { warn!("Update Weight DB error: {:?}", err); - return Err(UpdateWeightError::ServerError); + return Err(CommonWebError::from_anyhow_error(err)); } }