nomilo-archived/src/models/errors.rs

89 lines
2.7 KiB
Rust

use serde::Serialize;
use rocket::http::Status;
use rocket::request::{Request, Outcome};
use rocket::response::{self, Response, Responder};
use rocket_contrib::json::Json;
use crate::models::users::UserError;
use serde_json::Value;
#[derive(Serialize, Debug)]
pub struct ErrorResponse {
#[serde(with = "StatusDef")]
#[serde(flatten)]
pub status: Status,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<Value>
}
#[derive(Serialize)]
#[serde(remote = "Status")]
struct StatusDef {
code: u16,
#[serde(rename = "status")]
reason: &'static str,
}
impl ErrorResponse {
pub fn new(status: Status, message: String) -> ErrorResponse {
ErrorResponse {
status,
message,
details: None,
}
}
pub fn with_details<T: Serialize> (self, details: T) -> ErrorResponse {
ErrorResponse {
details: serde_json::to_value(details).ok(),
..self
}
}
pub fn err<R>(self) -> Result<R, ErrorResponse> {
Err(self)
}
}
impl<'r> Responder<'r, 'static> for ErrorResponse {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
let status = self.status;
Response::build_from(Json(self).respond_to(req)?).status(status).ok()
}
}
impl From<UserError> for ErrorResponse {
fn from(e: UserError) -> Self {
match e {
UserError::NotFound => ErrorResponse::new(Status::Unauthorized, "Provided credentials or token do not match any existing user".into()),
UserError::UserExists => ErrorResponse::new(Status::Conflict, "User already exists".into()),
UserError::BadToken => ErrorResponse::new(Status::BadRequest, "Malformed token".into()),
UserError::ExpiredToken => ErrorResponse::new(Status::Unauthorized, "The provided token has expired".into()),
UserError::MalformedHeader => ErrorResponse::new(Status::BadRequest, "Malformed authorization header".into()),
UserError::PermissionDenied => ErrorResponse::new(Status::Forbidden, "Bearer is not authorized to access the resource".into()),
UserError::DbError(e) => make_500(e),
UserError::PasswordError(e) => make_500(e)
}
}
}
impl<S> From<ErrorResponse> for Outcome<S, ErrorResponse> {
fn from(e: ErrorResponse) -> Self {
Outcome::Failure(e.into())
}
}
impl From<ErrorResponse> for (Status, ErrorResponse) {
fn from(e: ErrorResponse) -> Self {
(e.status, e)
}
}
pub fn make_500<E: std::fmt::Debug>(e: E) -> ErrorResponse {
println!("Making 500 for Error: {:?}", e);
ErrorResponse::new(Status::InternalServerError, "An unexpected error occured.".into())
}