// Copyright (C) 2022 Aravinth Manivannan // SPDX-FileCopyrightText: 2023 Aravinth Manivannan // // SPDX-License-Identifier: AGPL-3.0-or-later use std::fmt; use actix_web::{ error::ResponseError, http::{header::ContentType, StatusCode}, HttpResponse, HttpResponseBuilder, }; use derive_more::Display; use derive_more::Error; use serde::*; use super::TemplateFile; use crate::errors::ServiceError; pub const ERROR_KEY: &str = "error"; pub const ERROR_TEMPLATE: TemplateFile = TemplateFile::new("error_comp", "components/error/index.html"); pub fn register_templates(t: &mut tera::Tera) { ERROR_TEMPLATE.register(t).expect(ERROR_TEMPLATE.name); } /// Render template with error context pub trait CtxError { fn with_error(&self, e: &ReadableError) -> String; } #[derive(Serialize, Debug, Display, Clone)] #[display(fmt = "title: {} reason: {}", title, reason)] pub struct ReadableError { pub reason: String, pub title: String, } impl ReadableError { pub fn new(e: &ServiceError) -> Self { let reason = format!("{}", e); let title = format!("{}", e.status_code()); Self { reason, title } } } #[derive(Error, Display)] #[display(fmt = "{}", readable)] pub struct PageError { #[error(not(source))] template: T, readable: ReadableError, #[error(not(source))] error: ServiceError, } impl fmt::Debug for PageError { #[cfg(not(tarpaulin_include))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PageError") .field("readable", &self.readable) .finish() } } impl PageError { /// create new instance of [PageError] from a template and an error pub fn new(template: T, error: ServiceError) -> Self { let readable = ReadableError::new(&error); Self { error, template, readable, } } } #[cfg(not(tarpaulin_include))] impl ResponseError for PageError { fn error_response(&self) -> HttpResponse { HttpResponseBuilder::new(self.status_code()) .content_type(ContentType::html()) .body(self.template.with_error(&self.readable)) } fn status_code(&self) -> StatusCode { self.error.status_code() } } /// Generic result data structure #[cfg(not(tarpaulin_include))] pub type PageResult = std::result::Result>;