use axum::response::IntoResponse;
use http::StatusCode;
use crate::authorization::domain::action::Action;
use crate::authorization::domain::resource::ResourceIdentifier;
use crate::authorization::domain::resource::ResourceType;
use crate::user::domain::User;
#[derive(Debug, Clone, thiserror::Error)]
pub enum ApiError {
#[error("unable to extract router state")]
StateExtraction,
#[error("unable to find resource: {resource_name}")]
ResourceNotFound { resource_name: String },
#[error("{} is not authorized to {} the {:?}: {:?}", user.name, action, resource_type, resource_identifier)]
NotAuthorized {
user: Box<User>,
action: Action,
resource_identifier: Option<ResourceIdentifier>,
resource_type: ResourceType,
},
#[error("user is not authenticated")]
NotAuthenticated,
#[error("the server is not configured correctly: {message}")]
ServerConfiguration { message: String },
#[error("there is an issue with the the server infrastructure: {message}")]
Infrastucture { message: String },
}
impl IntoResponse for ApiError {
fn into_response(self) -> axum::response::Response {
tracing::error!("{self}");
match self {
ApiError::StateExtraction
| ApiError::ServerConfiguration { .. }
| ApiError::Infrastucture { .. } => (StatusCode::INTERNAL_SERVER_ERROR).into_response(),
ApiError::ResourceNotFound { .. } => {
(StatusCode::NOT_FOUND, self.to_string()).into_response()
}
ApiError::NotAuthorized { .. } => {
(StatusCode::FORBIDDEN, self.to_string()).into_response()
}
ApiError::NotAuthenticated => (StatusCode::UNAUTHORIZED).into_response(),
}
}
}