299 lines
10 KiB
Rust
299 lines
10 KiB
Rust
use git::GitError;
|
|
|
|
#[derive(Debug)]
|
|
pub enum AppError {
|
|
UserNotFound,
|
|
RsaGenerationError,
|
|
RsaDecodeError,
|
|
CaptchaError,
|
|
TwoFactorRequired,
|
|
Unauthorized,
|
|
DoMainNotSet,
|
|
UserNameExists,
|
|
EmailExists,
|
|
AccountAlreadyExists,
|
|
TxnError,
|
|
PasswordHashError(String),
|
|
TwoFactorAlreadyEnabled,
|
|
TwoFactorNotSetup,
|
|
InvalidTwoFactorCode,
|
|
TwoFactorNotEnabled,
|
|
DatabaseError(String),
|
|
InvalidPassword,
|
|
PasswordTooWeak,
|
|
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),
|
|
Conflict(String),
|
|
InvalidResetToken,
|
|
ResetTokenExpired,
|
|
ResetTokenUsed,
|
|
}
|
|
|
|
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,
|
|
InvalidResetToken => 40014,
|
|
ResetTokenExpired => 40015,
|
|
ResetTokenUsed => 40016,
|
|
PasswordTooWeak => 40011,
|
|
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,
|
|
AccountAlreadyExists => 40910,
|
|
ProjectNameAlreadyExists => 40903,
|
|
RepoNameAlreadyExists => 40905,
|
|
TwoFactorAlreadyEnabled => 40904,
|
|
Conflict(_) => 40909,
|
|
TwoFactorRequired => 42801,
|
|
DoMainNotSet => 50001,
|
|
TxnError => 50002,
|
|
RsaGenerationError => 50003,
|
|
PasswordHashError(_) => 50004,
|
|
DatabaseError(_) => 50005,
|
|
GitError(_) => 50006,
|
|
Io(_) => 50007,
|
|
InternalError => 50008,
|
|
InternalServerError(_) => 50009,
|
|
AvatarUploadError(_) => 50010,
|
|
}
|
|
}
|
|
|
|
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,
|
|
InvalidResetToken => 400,
|
|
ResetTokenExpired => 400,
|
|
ResetTokenUsed => 400,
|
|
PasswordTooWeak => 400,
|
|
Unauthorized => 401,
|
|
InvalidTwoFactorCode => 401,
|
|
InvalidPassword => 401,
|
|
NoPower => 403,
|
|
PermissionDenied => 403,
|
|
Forbidden(_) => 403,
|
|
RepoForBidAccess => 403,
|
|
NotFound(_) => 404,
|
|
UserNotFound => 404,
|
|
ProjectNotFound => 404,
|
|
RepoNotFound => 404,
|
|
UserNameExists => 409,
|
|
EmailExists => 409,
|
|
AccountAlreadyExists => 409,
|
|
ProjectNameAlreadyExists => 409,
|
|
RepoNameAlreadyExists => 409,
|
|
TwoFactorAlreadyEnabled => 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",
|
|
AccountAlreadyExists => "account_already_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",
|
|
PasswordTooWeak => "password_too_weak",
|
|
NoPower => "no_power",
|
|
PermissionDenied => "permission_denied",
|
|
Forbidden(_) => "forbidden",
|
|
RepoForBidAccess => "repo_forbidden",
|
|
TwoFactorAlreadyEnabled => "two_factor_already_enabled",
|
|
Conflict(_) => "conflict",
|
|
InvalidResetToken => "invalid_reset_token",
|
|
ResetTokenExpired => "reset_token_expired",
|
|
ResetTokenUsed => "reset_token_used",
|
|
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(s) => {
|
|
tracing::error!(error = %s, "database error");
|
|
"A database error occurred".to_string()
|
|
}
|
|
AppError::PasswordHashError(s) => {
|
|
tracing::error!(error = %s, "password hash error");
|
|
"A password processing error occurred".to_string()
|
|
}
|
|
AppError::GitError(s) => {
|
|
tracing::error!(error = %s, "git error");
|
|
"A git error occurred".to_string()
|
|
}
|
|
AppError::SerdeError(s) => {
|
|
tracing::error!(error = %s, "serde error");
|
|
"A data parsing error occurred".to_string()
|
|
}
|
|
AppError::Io(s) => {
|
|
tracing::error!(error = %s, "io error");
|
|
"A file system error occurred".to_string()
|
|
}
|
|
AppError::InternalServerError(e) => {
|
|
tracing::error!(error = %e, "internal server error");
|
|
"An internal server error occurred".to_string()
|
|
}
|
|
AppError::AvatarUploadError(s) => {
|
|
tracing::error!(error = %s, "avatar upload error");
|
|
"An avatar upload error occurred".to_string()
|
|
}
|
|
AppError::Conflict(s) => {
|
|
tracing::error!(error = %s, "resource conflict");
|
|
"Resource conflict".to_string()
|
|
}
|
|
_ => self.slug().to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for AppError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.user_message())
|
|
}
|
|
}
|
|
|
|
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) => {
|
|
tracing::error!(error = %e, "room database error");
|
|
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),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<agent::AgentError> for AppError {
|
|
fn from(e: agent::AgentError) -> Self {
|
|
match e {
|
|
agent::AgentError::NotFound(s) => AppError::NotFound(s),
|
|
agent::AgentError::InvalidInput { field, reason } => {
|
|
AppError::BadRequest(format!("invalid {}: {}", field, reason))
|
|
}
|
|
_ => AppError::InternalServerError(e.to_string()),
|
|
}
|
|
}
|
|
}
|