consolidate more error types (#1572)

This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-05-25 22:55:29 -04:00
1 parent 8ecc8cf7b3
commit a7b9ec1d95
97 files changed
+823 -3616

No files matched your search

@@ -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,
@@ -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<CreateApiTokenRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CreateApiTokenError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<DeleteApiTokenPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, DeleteApiTokenError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<EditApiTokenRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EditApiTokenError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<Arc<ServerState>>) -> Result<HttpResponse, ListApiTokensError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<CreateCategoryRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CreateCategoryError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<GetCategoryPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetCategoryError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<Arc<ServerState>>) -> Result<HttpResponse, ListTtsCategoriesError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<ListTtsModelAssignedCategoriesPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, ListTtsModelAssignedCategoriesError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<GetScenePathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetSceneError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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<GetSceneSuccessResponse, GetSceneError> {
) -> Result<GetSceneSuccessResponse, CommonWebError> {
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,
};
@@ -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<EventRecord>,
}
#[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<Arc<ServerState>>
) -> Result<HttpResponse, ListEventsError> {
) -> Result<HttpResponse, CommonWebError> {
// 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")
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<ListUserMediaUploadsOfTypeProfilePathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListUserMediaUploadsOfTypeError>
) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<DeleteCategoryPathInfo>,
request: web::Json<DeleteCategoryRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, DeleteCategoryError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<EditCategoryPathInfo>,
request: web::Json<EditCategoryRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EditCategoryError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<QueryParams>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, ListTtsCategoriesForModerationError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<QueryFields>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<HttpResponse, GetOnPremWorkerStatsError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<Arc<ServerState>>
) -> Result<HttpResponse, GetVoiceCountStatsError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<UserRoleForList>,
}
#[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<Arc<ServerState>>
) -> Result<HttpResponse, ListUserRolesError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<Arc<ServerState>>
) -> Result<HttpResponse, ListStaffError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<SetUserRolePathInfo>,
request: web::Json<SetUserRoleRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetUserRoleError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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));
}
};
@@ -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<Arc<ServerState>>) -> Result<HttpResponse, AppModelDownloadsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
// 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")
@@ -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<Arc<ServerState>>) -> Result<HttpResponse, AppNewsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
// 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")
@@ -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<Arc<ServerState>>) -> Result<HttpResponse, AppPlansError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<PostAppAnalyticsRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, PostAppAnalyticsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<GetVocoderPathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, GetVocoderError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<DateTime<Utc>>,
pub mod_deleted_at: Option<DateTime<Utc>>,
}
#[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<Arc<ServerState>>
) -> Result<HttpResponse, ListVocodersError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<String>,
}
#[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<CreateBetaKeysRequest>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<HttpResponse, CreateBetaKeysError>
) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<EditBetaKeyDistributedFlagRequest>,
path: Path<EditBetaKeyDistributedFlagPathInfo>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<HttpResponse, EditBetaKeyDistributedFlagError>
) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<EditBetaKeyNoteRequest>,
path: Path<EditBetaKeyNotePathInfo>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<HttpResponse, EditBetaKeyNoteError>
) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<DateTime<Utc>>,
}
#[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<ListBetaKeysQueryParams>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListBetaKeysError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<CreateFeaturedItemRequest>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<HttpResponse, CreateFeaturedItemError>
) -> Result<HttpResponse, 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
@@ -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")
@@ -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<DeleteFeaturedItemRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteFeaturedItemError> {
) -> Result<HttpResponse, 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
@@ -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));
}
};
@@ -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<GetIsFeaturedItemPathInfo>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<GetIsFeaturedItemSuccessResponse>, GetIsFeaturedItemError>
) -> Result<Json<GetIsFeaturedItemSuccessResponse>, 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 {
@@ -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<UpdateGptImageJobStatusRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<Json<UpdateGptImageJobStatusSuccessResponse>, UpdateGptImageJobStatusError>
server_state: web::Data<Arc<ServerState>>) -> Result<Json<UpdateGptImageJobStatusSuccessResponse>, 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);
@@ -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<KillInferenceJobsRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, KillInferenceJobsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<TerminateInferenceJobPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, TerminateInferenceJobError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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()
@@ -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<MediaFileTokenPathInfo>,
request: Json<ChangeMediaFileAnimationTypeRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<Json<SimpleResponse>, ChangeMediaFileAnimationTypeError> {
) -> Result<Json<SimpleResponse>, 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));
}
};
@@ -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<MediaFileTokenPathInfo>,
request: Json<ChangeMediaFileEngineCategoryRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<Json<SimpleResponse>, ChangeMediaFileEngineCategoryError> {
) -> Result<Json<SimpleResponse>, 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));
}
};
@@ -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<MediaFileTokenPathInfo>,
request: web::Json<ChangeMediaFileVisibilityRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, ChangeMediaFileVisibilityError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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));
}
};
@@ -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<MediaFileTokenPathInfo>,
request: web::Json<RenameMediaFileRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, RenameMediaFileError>{
) -> Result<HttpResponse, CommonWebError>{
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())
@@ -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<MediaFileTokenPathInfo>,
request: web::Json<SetMediaFileCoverImageRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, SetMediaFileCoverImageError>{
) -> Result<HttpResponse, CommonWebError>{
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));
}
};
@@ -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<UpdateMediaFilePathInfo>,
request: web::Json<UpdateMediaFileRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, UpdateMediaFileError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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));
}
};
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<SearchFeaturedMediaFilesQueryParams>,
server_state: web::Data<Arc<ServerState>>
) -> Result<Json<SearchFeaturedMediaFilesSuccessResponse>, SearchFeaturedMediaFilesError>
) -> Result<Json<SearchFeaturedMediaFilesSuccessResponse>, 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));
}
};
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<SearchMediaFilesQueryParams>,
server_state: web::Data<Arc<ServerState>>
) -> Result<Json<SearchMediaFilesSuccessResponse>, SearchMediaFilesError>
) -> Result<Json<SearchMediaFilesSuccessResponse>, 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));
}
};
@@ -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<Arc<ServerState>>
) -> Result<Json<DetectLocaleResponse>, DetectLocaleError> {
) -> Result<Json<DetectLocaleResponse>, CommonWebError> {
let locale = get_user_locale(&http_request);
Ok(Json(DetectLocaleResponse {
@@ -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<String>,
}
#[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<ModeratorTokenInfoPath>,
http_request: HttpRequest,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ModeratorTokenInfoError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<String>,
}
#[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<AddIpBanRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, AddIpBanError> {
) -> Result<HttpResponse, CommonWebError> {
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())
@@ -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<DeleteIpBanPathInfo>,
request: web::Json<DeleteIpBanRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteIpBanError> {
) -> Result<HttpResponse, CommonWebError> {
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));
}
};
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<GetIpBanPathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, GetIpBanError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<Arc<ServerState>>
) -> Result<HttpResponse, ListIpBansError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<Arc<ServerState>>
) -> Result<HttpResponse, GetTtsInferenceQueueCountError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<KillTtsInferenceJobsRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, KillTtsInferenceJobsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<EditUserFeatureFlagsRequest>,
server_state: Data<Arc<ServerState>>,
redis_pool: Data<r2d2::Pool<Client>>,
) -> Result<HttpResponse, EditUserFeatureFlagsError> {
) -> Result<HttpResponse, CommonWebError> {
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.
@@ -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<Arc<ServerState>>
) -> Result<Json<PublicInfoResponse>, PublicInfoError> {
) -> Result<Json<PublicInfoResponse>, CommonWebError> {
let server_info = get_server_info(&server_state);
Ok(Json(PublicInfoResponse {
success: true,
@@ -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<Arc<ServerState>>
) -> Result<Json<StatusAlertResponse>, StatusAlertError> {
) -> Result<Json<StatusAlertResponse>, CommonWebError> {
let maybe_alert = get_status_alert(&server_state);
@@ -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<SetUnsubscribeReasonRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetUnsubscribeReasonError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<TagInfo>,
}
#[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<ListTagsForEntityPathInfo>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<ListTagsForEntitySuccessResponse>, ListTagsForEntityError>
) -> Result<Json<ListTagsForEntitySuccessResponse>, 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));
@@ -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<TagInfo>,
}
#[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<SetTagsForEntityRequest>,
path: Path<SetTagsForEntityPathInfo>,
server_state: Data<Arc<ServerState>>,
) -> Result<Json<SetTagsForEntitySuccessResponse>, SetTagsForEntityError>
) -> Result<Json<SetTagsForEntitySuccessResponse>, 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::<Vec<TagInfo>>())
.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<bool, SetTagsForEntityError> {
) -> Result<bool, CommonWebError> {
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))
}
}
}
@@ -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<WindowName, Vec<TtsModelToken>>;
// =============== 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<Arc<ServerState>>) -> Result<HttpResponse, ListTrendingTtsModelsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
// 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")
@@ -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<bool>,
}
#[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<DeleteTtsModelPathInfo>,
request: web::Json<DeleteTtsModelRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteTtsModelError> {
) -> Result<HttpResponse, CommonWebError> {
// 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));
}
};
@@ -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<bool>,
}
#[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<DeleteTtsInferenceResultPathInfo>,
request: web::Json<DeleteTtsInferenceResultRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteTtsInferenceResultError> {
) -> Result<HttpResponse, CommonWebError> {
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));
}
};
@@ -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<Arc<ServerState>>
) -> Result<HttpResponse, GetPendingTtsInferenceJobCountError> {
) -> Result<HttpResponse, CommonWebError> {
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<HttpResponse, GetPendingTtsInferenceJobCountError> {
pub fn render_response_busy(response: Response) -> Result<HttpResponse, CommonWebError> {
let body = render_response_payload(response)?;
Ok(HttpResponse::TooManyRequests()
.content_type("application/json")
.body(body))
}
pub fn render_response_ok(response: Response) -> Result<HttpResponse, GetPendingTtsInferenceJobCountError> {
pub fn render_response_ok(response: Response) -> Result<HttpResponse, CommonWebError> {
let body = render_response_payload(response)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
pub fn render_response_payload(response: Response) -> Result<String, GetPendingTtsInferenceJobCountError> {
pub fn render_response_payload(response: Response) -> Result<String, CommonWebError> {
let body = serde_json::to_string(&response)
.map_err(|e| {
error!("error returning response: {:?}", e);
GetPendingTtsInferenceJobCountError::ServerError
CommonWebError::from_error(e)
})?;
Ok(body)
}
@@ -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<GetTtsInferenceStatusPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetTtsInferenceStatusError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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<TtsInferenceJobStatusForResponse, GetTtsInferenceStatusError>
-> Result<TtsInferenceJobStatusForResponse, CommonWebError>
{
// 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<TtsInferenceJobStatusForResponse, GetTtsInferenceStatusError>
-> Result<TtsInferenceJobStatusForResponse, CommonWebError>
{
// 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.
@@ -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<GetTtsModelPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetTtsModelError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<GetTtsResultPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetTtsResultError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<GetTtsUploadModelStatusPathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetTtsUploadModelStatusError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
// 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")
@@ -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<TtsModelRecordForResponse>,
}
#[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<Arc<ServerState>>) -> Result<HttpResponse, ListTtsModelsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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<HttpResponse, ListTtsModelsError> {
pub fn render_response_busy(response: ListTtsModelsSuccessResponse) -> Result<HttpResponse, CommonWebError> {
let body = render_response_payload(response)?;
Ok(HttpResponse::TooManyRequests()
.content_type("application/json")
.body(body))
}
pub fn render_response_ok(response: ListTtsModelsSuccessResponse) -> Result<HttpResponse, ListTtsModelsError> {
pub fn render_response_ok(response: ListTtsModelsSuccessResponse) -> Result<HttpResponse, CommonWebError> {
let body = render_response_payload(response)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
pub fn render_response_payload(response: ListTtsModelsSuccessResponse) -> Result<String, ListTtsModelsError> {
pub fn render_response_payload(response: ListTtsModelsSuccessResponse) -> Result<String, CommonWebError> {
let body = serde_json::to_string(&response)
.map_err(|e| {
error!("error returning response: {:?}", e);
ListTtsModelsError::ServerError
CommonWebError::from_error(e)
})?;
Ok(body)
}
@@ -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<String>,
pub cursor_previous: Option<String>,
}
#[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<ListTtsInferenceResultsForUserPathInfo>,
query: Query<ListTtsInferenceResultsForUserQuery>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListTtsInferenceResultsForUserError>
) -> Result<HttpResponse, CommonWebError>
{
return Ok(HttpResponse::Gone()
.content_type(ContentType::plaintext())
@@ -80,7 +53,7 @@ pub async fn list_user_tts_inference_results_handler(
path: Path<ListTtsInferenceResultsForUserPathInfo>,
query: Query<ListTtsInferenceResultsForUserQuery>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListTtsInferenceResultsForUserError>
) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<TtsModelRecordForList>,
}
#[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<GetProfilePathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListTtsModelsForUserError>
) -> Result<HttpResponse, CommonWebError>
{
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<GetProfilePathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListTtsModelsForUserError>
) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<TtsModel>,
}
#[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<SearchTtsModelsRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SearchTtsModelsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<BatchGetUserRatingQueryParams>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, BatchGetUserRatingError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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<T>.
@@ -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()
@@ -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<GetUserRatingPath>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, GetUserRatingError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<SetUserRatingRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetUserRatingError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, 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
@@ -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")
@@ -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<ChangePasswordRequest>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<ChangePasswordResponse>, ChangePasswordError>
) -> Result<Json<ChangePasswordResponse>, 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));
}
}
@@ -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<EditEmailRequest>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<EditEmailResponse>, EditEmailError>
) -> Result<Json<EditEmailResponse>, 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"));
}
}
@@ -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<EditUsernameRequest>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<EditUsernameResponse>, EditUsernameError>
) -> Result<Json<EditUsernameResponse>, 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"));
}
}
@@ -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<UserProfileRecordForResponse>,
}
#[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<MySqlPool>,
redis_pool: web::Data<r2d2::Pool<Client>>,
session_checker: web::Data<SessionChecker>,
) -> Result<HttpResponse, ProfileError>
) -> Result<HttpResponse, CommonWebError>
{
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();
@@ -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<HttpUserSessionManager>,
mysql_pool: web::Data<MySqlPool>,
internal_session_cache_purge: web::Data<dyn InternalSessionCachePurge>,
) -> Result<HttpResponse, LogoutError>
) -> Result<HttpResponse, CommonWebError>
{
// 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();
@@ -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<String>,
}
#[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<SessionChecker>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<SessionTokenInfoSuccessResponse>, SessionTokenInfoError>
) -> Result<Json<SessionTokenInfoSuccessResponse>, 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 {
@@ -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<CheckIfVoiceRequestSubmittedRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CheckIfVoiceRequestSubmittedError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<CreateVoiceRequestRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CreateVoiceRequestError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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")
@@ -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<VoiceConversionModel>,
}
#[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<Arc<ServerState>>) -> Result<HttpResponse, ListVoiceConversionModelsError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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<HttpResponse, ListVoiceConversionModelsError> {
pub fn render_response_busy(response: ListVoiceConversionModelsSuccessResponse) -> Result<HttpResponse, CommonWebError> {
let body = render_response_payload(response)?;
Ok(HttpResponse::TooManyRequests()
.content_type("application/json")
.body(body))
}
pub fn render_response_ok(response: ListVoiceConversionModelsSuccessResponse) -> Result<HttpResponse, ListVoiceConversionModelsError> {
pub fn render_response_ok(response: ListVoiceConversionModelsSuccessResponse) -> Result<HttpResponse, CommonWebError> {
let body = render_response_payload(response)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
pub fn render_response_payload(response: ListVoiceConversionModelsSuccessResponse) -> Result<String, ListVoiceConversionModelsError> {
pub fn render_response_payload(response: ListVoiceConversionModelsSuccessResponse) -> Result<String, CommonWebError> {
let body = serde_json::to_string(&response)
.map_err(|e| {
error!("error returning response: {:?}", e);
ListVoiceConversionModelsError::ServerError
CommonWebError::from_error(e)
})?;
Ok(body)
}
@@ -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<bool>,
}
#[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<DeleteSamplePathInfo>,
request: web::Json<DeleteSampleRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteSampleError> {
) -> Result<HttpResponse, CommonWebError> {
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));
}
};
@@ -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<ListSamplesByDatasetPathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListSamplesByDatasetError> {
) -> Result<HttpResponse, CommonWebError> {
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))
@@ -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<CreateDatasetRequest>, server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CreateDatasetError> {
pub async fn create_dataset_handler(http_request: HttpRequest, request: web::Json<CreateDatasetRequest>, server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<DeleteDatasetPathInfo>,
request: web::Json<DeleteDatasetRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteDatasetError>{
) -> Result<HttpResponse, CommonWebError>{
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));
}
};
@@ -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<GetDatasetPathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, GetDatasetError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<UpdateDatasetPathInfo>,
request: web::Json<UpdateDatasetRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, UpdateDatasetError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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));
}
};
@@ -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<DeleteVoicePathInfo>,
request: web::Json<DeleteVoiceRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteVoiceError>{
) -> Result<HttpResponse, CommonWebError>{
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));
}
};
@@ -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<GetVoicePathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, GetVoiceError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<Utc>,
pub updated_at: DateTime<Utc>,
}
#[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<ListZsVoicesQuery>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListZsVoicesError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<UpdateVoicePathInfo>,
request: web::Json<UpdateVoiceRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, UpdateVoiceError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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));
}
};
@@ -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<DeleteWeightPathInfo>,
request: web::Json<DeleteWeightRequest>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, DeleteWeightError>{
) -> Result<HttpResponse, CommonWebError>{
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));
}
};
@@ -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<GetWeightPathInfo>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, GetWeightError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<ListWeightsByUserPathInfo>,
query: Query<ListWeightsForUserQueryParams>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListWeightsByUserError> {
) -> Result<HttpResponse, CommonWebError> {
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")
@@ -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<SetModelWeightCoverImagePathInfo>,
request: web::Json<SetModelWeightCoverImageRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetModelWeightCoverImageError>
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CommonWebError>
{
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));
}
};
@@ -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<UpdateWeightRequest>,
mysql_pool: web::Data<MySqlPool>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, UpdateWeightError> {
) -> Result<HttpResponse, CommonWebError> {
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));
}
}