diff --git a/src/errors.rs b/src/errors.rs index 0bbb6a61..51459c07 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -198,38 +198,6 @@ pub enum PageError { InternalServerError, } -use sailfish::TemplateOnce; - -#[derive(Clone, TemplateOnce)] -#[template(path = "errors/internal-server-error.html")] -struct ErrorPage<'a> { - title: &'a str, - message: &'a str, -} - -const PAGE: &str = "Error"; - -impl<'a> ErrorPage<'a> { - fn new(title: &'a str, message: &'a str) -> Self { - ErrorPage { title, message } - } -} - -lazy_static! { - static ref INTERNAL_SERVER_ERROR: String = ErrorPage::new( - "Internal Server Error", - &format!("{}", PageError::InternalServerError) - ) - .render_once() - .unwrap(); - static ref UNKNOWN_ERROR: String = ErrorPage::new( - "Server Error", - &format!("{}", PageError::InternalServerError) - ) - .render_once() - .unwrap(); -} - #[cfg(not(tarpaulin_include))] impl From for PageError { #[cfg(not(tarpaulin_include))] @@ -239,15 +207,18 @@ impl From for PageError { } impl ResponseError for PageError { - #[cfg(not(tarpaulin_include))] fn error_response(&self) -> HttpResponse { - let body = match self.status_code() { - StatusCode::INTERNAL_SERVER_ERROR => &*INTERNAL_SERVER_ERROR, - _ => &*UNKNOWN_ERROR, - }; - HttpResponseBuilder::new(self.status_code()) - .content_type("text/html; charset=utf-8") - .body(body) + use crate::PAGES; + match self.status_code() { + StatusCode::INTERNAL_SERVER_ERROR => HttpResponse::Found() + .header(header::LOCATION, PAGES.errors.internal_server_error) + .finish() + .into(), + _ => HttpResponse::Found() + .header(header::LOCATION, PAGES.errors.unknown_error) + .finish() + .into(), + } } #[cfg(not(tarpaulin_include))] @@ -264,10 +235,16 @@ pub type PageResult = std::result::Result; #[cfg(test)] mod tests { use super::*; + use crate::PAGES; #[test] fn error_works() { let resp: HttpResponse = PageError::InternalServerError.error_response(); - assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); + assert_eq!(resp.status(), StatusCode::FOUND); + let headers = resp.headers(); + assert_eq!( + headers.get(header::LOCATION).unwrap(), + PAGES.errors.internal_server_error + ); } } diff --git a/src/pages/errors.rs b/src/pages/errors.rs new file mode 100644 index 00000000..1926ea31 --- /dev/null +++ b/src/pages/errors.rs @@ -0,0 +1,119 @@ +/* +* Copyright (C) 2021 Aravinth Manivannan +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +use actix_web::{web, HttpResponse, Responder}; +use lazy_static::lazy_static; +use sailfish::TemplateOnce; + +use crate::errors::PageError; + +#[derive(Clone, TemplateOnce)] +#[template(path = "errors/index.html")] +struct ErrorPage<'a> { + title: &'a str, + message: &'a str, +} + +const PAGE: &str = "Error"; + +impl<'a> ErrorPage<'a> { + fn new(title: &'a str, message: &'a str) -> Self { + ErrorPage { title, message } + } +} + +lazy_static! { + static ref INTERNAL_SERVER_ERROR_BODY: String = ErrorPage::new( + "Internal Server Error", + &format!("{}", PageError::InternalServerError), + ) + .render_once() + .unwrap(); + static ref UNKNOWN_ERROR_BODY: String = ErrorPage::new( + "Something went wrong", + &format!("{}", PageError::InternalServerError), + ) + .render_once() + .unwrap(); +} + +async fn error(path: web::Path) -> impl Responder { + let resp = match path.0 { + 500 => HttpResponse::InternalServerError() + .content_type("text/html; charset=utf-8") + .body(&*INTERNAL_SERVER_ERROR_BODY), + + _ => HttpResponse::InternalServerError() + .content_type("text/html; charset=utf-8") + .body(&*UNKNOWN_ERROR_BODY), + }; + + resp +} + +pub fn services(cfg: &mut web::ServiceConfig) { + use crate::define_resource; + + define_resource!(cfg, "/error/{id}", Methods::Get, error); +} + +pub mod routes { + pub struct Errors { + pub internal_server_error: &'static str, + pub unknown_error: &'static str, + } + + impl Errors { + pub const fn new() -> Self { + Errors { + internal_server_error: "/error/500", + unknown_error: "/error/007", + } + } + } +} + +#[cfg(test)] +mod tests { + use actix_web::{http::StatusCode, test, App}; + + use super::*; + use crate::PAGES; + + #[actix_rt::test] + async fn error_pages_work() { + let mut app = test::init_service(App::new().configure(services)).await; + + let resp = test::call_service( + &mut app, + test::TestRequest::get() + .uri(PAGES.errors.internal_server_error) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); + + let resp = test::call_service( + &mut app, + test::TestRequest::get() + .uri(PAGES.errors.unknown_error) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); + } +} diff --git a/src/pages/mod.rs b/src/pages/mod.rs index 1ace6cb6..ac351821 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -18,6 +18,7 @@ use actix_web::web::ServiceConfig; mod auth; +pub mod errors; mod panel; pub mod routes; @@ -26,6 +27,7 @@ pub const NAME: &str = "mCaptcha"; pub fn services(cfg: &mut ServiceConfig) { auth::services(cfg); panel::services(cfg); + errors::services(cfg); } #[cfg(not(tarpaulin_include))] diff --git a/src/pages/routes.rs b/src/pages/routes.rs index 66321d57..d0d61ec2 100644 --- a/src/pages/routes.rs +++ b/src/pages/routes.rs @@ -16,6 +16,7 @@ */ use super::auth::routes::Auth; +use super::errors::routes::Errors; use super::panel::routes::Panel; pub const ROUTES: Routes = Routes::new(); @@ -23,6 +24,7 @@ pub struct Routes { pub home: &'static str, pub auth: Auth, pub panel: Panel, + pub errors: Errors, } impl Routes { @@ -33,6 +35,7 @@ impl Routes { auth: Auth::new(), panel, home, + errors: Errors::new(), } } } diff --git a/templates/errors/internal-server-error.html b/templates/errors/index.html similarity index 100% rename from templates/errors/internal-server-error.html rename to templates/errors/index.html