gitdataai/libs/service/error.rs
2026-04-14 19:02:01 +08:00

265 lines
9.2 KiB
Rust

use git::GitError;
#[derive(Debug)]
pub enum AppError {
UserNotFound,
RsaGenerationError,
RsaDecodeError,
CaptchaError,
TwoFactorRequired,
Unauthorized,
DoMainNotSet,
UserNameExists,
EmailExists,
TxnError,
PasswordHashError(String),
TwoFactorAlreadyEnabled,
TwoFactorNotSetup,
InvalidTwoFactorCode,
TwoFactorNotEnabled,
DatabaseError(String),
InvalidPassword,
ProjectNotFound,
NoPower,
InternalError,
NotFound(String),
RoleParseError,
ProjectNameAlreadyExists,
RepoNameAlreadyExists,
AvatarUploadError(String),
InternalServerError(String),
PermissionDenied,
RepoNotFound,
RepoForBidAccess,
GitError(GitError),
SerdeError(serde_json::Error),
Io(std::io::Error),
BadRequest(String),
Forbidden(String),
WorkspaceNotFound,
WorkspaceSlugAlreadyExists,
WorkspaceNameAlreadyExists,
NotWorkspaceMember,
WorkspaceInviteTokenInvalid,
WorkspaceInviteExpired,
WorkspaceInviteAlreadyAccepted,
Conflict(String),
}
impl AppError {
pub const fn code(&self) -> i32 {
use AppError::*;
match self {
BadRequest(_) => 40000,
CaptchaError => 40001,
SerdeError(_) => 40002,
RsaDecodeError => 40003,
RoleParseError => 40004,
TwoFactorNotSetup => 40005,
TwoFactorNotEnabled => 40006,
Unauthorized => 40101,
InvalidTwoFactorCode => 40102,
InvalidPassword => 40103,
NoPower => 40301,
PermissionDenied => 40302,
Forbidden(_) => 40304,
RepoForBidAccess => 40303,
NotFound(_) => 40401,
UserNotFound => 40402,
ProjectNotFound => 40403,
RepoNotFound => 40404,
UserNameExists => 40901,
EmailExists => 40902,
ProjectNameAlreadyExists => 40903,
RepoNameAlreadyExists => 40905,
TwoFactorAlreadyEnabled => 40904,
TwoFactorRequired => 42801,
DoMainNotSet => 50001,
TxnError => 50002,
RsaGenerationError => 50003,
PasswordHashError(_) => 50004,
DatabaseError(_) => 50005,
GitError(_) => 50006,
Io(_) => 50007,
InternalError => 50008,
InternalServerError(_) => 50009,
AvatarUploadError(_) => 50010,
WorkspaceNotFound => 40405,
WorkspaceSlugAlreadyExists => 40906,
WorkspaceNameAlreadyExists => 40907,
NotWorkspaceMember => 40305,
WorkspaceInviteTokenInvalid => 40006,
WorkspaceInviteExpired => 40007,
WorkspaceInviteAlreadyAccepted => 40908,
Conflict(_) => 40909,
}
}
pub const fn http_status_code(&self) -> u16 {
use AppError::*;
match self {
BadRequest(_) => 400,
CaptchaError => 400,
SerdeError(_) => 400,
RsaDecodeError => 400,
RoleParseError => 400,
TwoFactorNotSetup => 400,
TwoFactorNotEnabled => 400,
WorkspaceInviteTokenInvalid => 400,
WorkspaceInviteExpired => 400,
Unauthorized => 401,
InvalidTwoFactorCode => 401,
InvalidPassword => 401,
NoPower => 403,
PermissionDenied => 403,
Forbidden(_) => 403,
RepoForBidAccess => 403,
NotWorkspaceMember => 403,
NotFound(_) => 404,
UserNotFound => 404,
ProjectNotFound => 404,
RepoNotFound => 404,
WorkspaceNotFound => 404,
UserNameExists => 409,
EmailExists => 409,
ProjectNameAlreadyExists => 409,
RepoNameAlreadyExists => 409,
TwoFactorAlreadyEnabled => 409,
WorkspaceSlugAlreadyExists => 409,
WorkspaceNameAlreadyExists => 409,
WorkspaceInviteAlreadyAccepted => 409,
Conflict(_) => 409,
TwoFactorRequired => 428,
DoMainNotSet => 500,
TxnError => 500,
RsaGenerationError => 500,
PasswordHashError(_) => 500,
DatabaseError(_) => 500,
GitError(_) => 500,
Io(_) => 500,
InternalError => 500,
InternalServerError(_) => 500,
AvatarUploadError(_) => 500,
}
}
pub const fn slug(&self) -> &'static str {
use AppError::*;
match self {
Unauthorized => "unauthorized",
UserNotFound => "user_not_found",
ProjectNotFound => "project_not_found",
RepoNotFound => "repo_not_found",
NotFound(_) => "not_found",
TwoFactorRequired => "two_factor_required",
UserNameExists => "username_exists",
EmailExists => "email_exists",
ProjectNameAlreadyExists => "project_name_exists",
RepoNameAlreadyExists => "repo_name_exists",
CaptchaError => "captcha_error",
BadRequest(_) => "bad_request",
SerdeError(_) => "serde_error",
RsaDecodeError => "rsa_decode_error",
RoleParseError => "role_parse_error",
TwoFactorNotSetup => "two_factor_not_setup",
TwoFactorNotEnabled => "two_factor_not_enabled",
InvalidTwoFactorCode => "invalid_two_factor_code",
InvalidPassword => "invalid_password",
NoPower => "no_power",
PermissionDenied => "permission_denied",
Forbidden(_) => "forbidden",
RepoForBidAccess => "repo_forbidden",
TwoFactorAlreadyEnabled => "two_factor_already_enabled",
WorkspaceNotFound => "workspace_not_found",
WorkspaceSlugAlreadyExists => "workspace_slug_exists",
WorkspaceNameAlreadyExists => "workspace_name_exists",
NotWorkspaceMember => "not_workspace_member",
WorkspaceInviteTokenInvalid => "workspace_invite_token_invalid",
WorkspaceInviteExpired => "workspace_invite_expired",
WorkspaceInviteAlreadyAccepted => "workspace_invite_already_accepted",
Conflict(_) => "conflict",
DoMainNotSet => "domain_not_set",
TxnError => "transaction_error",
RsaGenerationError => "rsa_generation_error",
PasswordHashError(_) => "password_hash_error",
DatabaseError(_) => "database_error",
GitError(_) => "git_error",
Io(_) => "io_error",
InternalError => "internal_error",
InternalServerError(_) => "internal_server_error",
AvatarUploadError(_) => "avatar_upload_error",
}
}
pub fn user_message(&self) -> String {
match self {
AppError::NotFound(s) => s.clone(),
AppError::BadRequest(s) => s.clone(),
AppError::Forbidden(s) => s.clone(),
AppError::DatabaseError(_) => "A database error occurred".to_string(),
AppError::PasswordHashError(_) => "A password processing error occurred".to_string(),
AppError::GitError(_) => "A git operation failed".to_string(),
AppError::SerdeError(_) => "A data parsing error occurred".to_string(),
AppError::Io(_) => "A file system error occurred".to_string(),
AppError::InternalServerError(_) => "An internal error occurred".to_string(),
AppError::AvatarUploadError(_) => "An avatar upload error occurred".to_string(),
AppError::Conflict(_) => "Resource conflict".to_string(),
_ => self.slug().to_string(),
}
}
}
impl From<argon2::password_hash::Error> for AppError {
fn from(value: argon2::password_hash::Error) -> Self {
AppError::PasswordHashError(value.to_string())
}
}
impl From<sea_orm::error::DbErr> for AppError {
fn from(value: sea_orm::error::DbErr) -> Self {
AppError::DatabaseError(value.to_string())
}
}
impl From<GitError> for AppError {
fn from(value: GitError) -> Self {
AppError::GitError(value)
}
}
impl From<serde_json::Error> for AppError {
fn from(value: serde_json::Error) -> Self {
AppError::SerdeError(value)
}
}
impl From<std::io::Error> for AppError {
fn from(value: std::io::Error) -> Self {
AppError::Io(value)
}
}
impl From<anyhow::Error> for AppError {
fn from(value: anyhow::Error) -> Self {
AppError::InternalServerError(value.to_string())
}
}
impl From<room::RoomError> for AppError {
fn from(err: room::RoomError) -> Self {
use room::RoomError;
match err {
RoomError::Database(e) => {
println!("database error: {}", e);
AppError::DatabaseError(e.to_string())
}
RoomError::NotFound(s) => AppError::NotFound(s),
RoomError::Unauthorized => AppError::Unauthorized,
RoomError::NoPower => AppError::NoPower,
RoomError::RateLimited(s) => AppError::BadRequest(s),
RoomError::BadRequest(s) => AppError::BadRequest(s),
RoomError::RoleParseError => AppError::RoleParseError,
RoomError::Internal(s) => AppError::InternalServerError(s),
}
}
}