89 lines
2.7 KiB
Rust
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())
|
|
}
|