use actix_web::body::BoxBody; use actix_web::dev::ServiceResponse; use actix_web::http::header::ContentType; use actix_web::http::StatusCode; use actix_web::middleware::ErrorHandlerResponse; use actix_web::{web, HttpResponse, ResponseError}; use derive_more::{Display, Error}; use super::SharedData; use crate::template_utils::{render_template, ErrorMessage, TemplateArgs}; #[derive(Debug, Display, Error)] pub enum UserError { NotFound, #[display(fmt = "Internal error. Try again later.")] InternalError, } impl ResponseError for UserError { fn error_response(&self) -> HttpResponse { HttpResponse::build(self.status_code()) .insert_header(ContentType::html()) .body(self.to_string()) } fn status_code(&self) -> StatusCode { match *self { UserError::NotFound => StatusCode::NOT_FOUND, UserError::InternalError => StatusCode::INTERNAL_SERVER_ERROR, } } } pub fn generic_error( res: ServiceResponse, ) -> actix_web::Result> { let data = res .request() .app_data::>() .map(|t| t.get_ref()); let status_code = res.response().status(); let message = if let Some(error) = status_code.canonical_reason() { error } else { "" }; let response = match data { Some(SharedData { handlebars, config: _, }) => { let args = TemplateArgs::builder() .error_page(ErrorMessage::new(message, status_code.as_u16())) .build(); let body = render_template(handlebars, "error", &args) .map_err(|_| UserError::InternalError)?; HttpResponse::build(res.status()) .content_type(ContentType::html()) .body(body) } None => Err(UserError::InternalError)?, }; Ok(ErrorHandlerResponse::Response(ServiceResponse::new( res.into_parts().0, response.map_into_left_body(), ))) }