covert-userpass-auth 0.1.3

Covert userpass auth method
Documentation
use std::fmt::Display;

use covert_types::error::{ApiError, StatusCode};
use thiserror::Error;
use tracing_error::SpanTrace;

#[derive(Error, Debug)]
pub enum ErrorType {
    #[error("Internal error")]
    Storage(#[from] sqlx::Error),
    #[error("Bad request")]
    BadRequest(#[from] serde_json::Error),
    #[error("User with username: `{username}` not found")]
    UserNotFound { username: String },
    #[error("Incorrect password")]
    IncorrectPassword,
    #[error("Unsupported password")]
    UnsupportedPassword,
}

#[derive(Error, Debug)]
pub struct Error {
    pub variant: ErrorType,
    pub span_trace: SpanTrace,
}

impl Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}\n{}", self.variant, self.span_trace)
    }
}

impl From<sqlx::Error> for Error {
    fn from(err: sqlx::Error) -> Self {
        Self {
            variant: err.into(),
            span_trace: SpanTrace::capture(),
        }
    }
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Self {
        Self {
            variant: err.into(),
            span_trace: SpanTrace::capture(),
        }
    }
}

impl From<ErrorType> for Error {
    fn from(err: ErrorType) -> Self {
        Self {
            variant: err,
            span_trace: SpanTrace::capture(),
        }
    }
}

impl From<Error> for ApiError {
    fn from(err: Error) -> Self {
        let status_code = match err.variant {
            ErrorType::Storage(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ErrorType::BadRequest(_) | ErrorType::UnsupportedPassword => StatusCode::BAD_REQUEST,
            ErrorType::UserNotFound { .. } => StatusCode::NOT_FOUND,
            ErrorType::IncorrectPassword { .. } => StatusCode::UNAUTHORIZED,
        };

        ApiError {
            error: err.variant.into(),
            status_code,
            span_trace: Some(err.span_trace),
        }
    }
}