#![allow(clippy::module_name_repetitions)]
use crate::web;
use airlab_lib::model;
use airlab_lib::{pwd, token};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use derive_more::From;
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr};
use std::sync::Arc;
use tracing::debug;
pub type Result<T> = core::result::Result<T, Error>;
#[serde_as]
#[derive(Debug, Serialize, From, strum_macros::AsRefStr)]
#[serde(tag = "type", content = "data")]
pub enum Error {
LoginFailUsernameNotFound,
LoginFailUserHasNoPwd {
user_id: i32,
},
LoginFailPwdNotMatching {
user_id: i32,
},
#[from]
CtxExt(web::mw_auth::CtxExtError),
#[from]
Model(model::Error),
#[from]
Pwd(pwd::Error),
#[from]
Token(token::Error),
#[from]
Io(#[serde_as(as = "DisplayFromStr")] std::io::Error),
#[from]
SerdeJson(#[serde_as(as = "DisplayFromStr")] serde_json::Error),
}
impl IntoResponse for Error {
fn into_response(self) -> Response {
debug!("INFO_RES - model::Error {self:?}");
let mut response = StatusCode::INTERNAL_SERVER_ERROR.into_response();
response.extensions_mut().insert(Arc::new(self));
response
}
}
impl core::fmt::Display for Error {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
write!(fmt, "{self:?}")
}
}
impl std::error::Error for Error {}
impl Error {
pub const fn client_status_and_error(&self) -> (StatusCode, ClientError) {
use web::Error::{
CtxExt, LoginFailPwdNotMatching, LoginFailUserHasNoPwd, LoginFailUsernameNotFound,
Model,
};
#[allow(unreachable_patterns)]
match self {
LoginFailUsernameNotFound
| LoginFailUserHasNoPwd { .. }
| LoginFailPwdNotMatching { .. } => (StatusCode::FORBIDDEN, ClientError::LOGIN_FAIL),
CtxExt(_) => (StatusCode::FORBIDDEN, ClientError::NO_AUTH),
Model(model::Error::EntityNotFound { entity, id }) => (
StatusCode::BAD_REQUEST,
ClientError::ENTITY_NOT_FOUND { entity, id: *id },
),
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
ClientError::SERVICE_ERROR,
),
}
}
}
#[derive(Debug, Serialize, strum_macros::AsRefStr)]
#[serde(tag = "message", content = "detail")]
#[allow(non_camel_case_types)]
pub enum ClientError {
LOGIN_FAIL,
NO_AUTH,
ENTITY_NOT_FOUND { entity: &'static str, id: i32 },
SERVICE_ERROR,
}