diff --git a/Cargo.toml b/Cargo.toml index db79ff6..74cd1d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,15 @@ license-file = "LICENSE.txt" [dependencies] anyhow = "1.0" -axum = "0.5" +askama = { git = "https://github.com/djc/askama.git" } +askama_axum = { git = "https://github.com/djc/askama.git", package = "askama_axum" } +axum = { version = "0.5", default-features = false, features = [ + "http1", + "query", + "form", +] } captcha = "0.0.9" lettre = "0.10" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -tera = "1.17" tokio = { version = "1.21", features = ["full"] } diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..74bc4c9 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,16 @@ +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; + +pub struct AppError(anyhow::Error); + +impl IntoResponse for AppError { + fn into_response(self) -> Response { + StatusCode::BAD_REQUEST.into_response() + } +} + +impl From for AppError { + fn from(err: anyhow::Error) -> Self { + Self(err.into()) + } +} diff --git a/src/main.rs b/src/main.rs index 68d0db9..006ed55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,19 @@ mod captcha_solutions; mod config; -mod context; +mod errors; mod forms; mod mailer; mod routes; +mod templates; -use anyhow::{Context, Result}; +use anyhow::Result; use axum::extract::Extension; use axum::routing::{get, post}; use axum::{Router, Server}; use std::process; use std::sync::Arc; -use tera::Tera; async fn init() -> Result<()> { - let tera = Arc::new(Tera::new("templates/*").context("Failed to parse templates!")?); - let mut config = config::Config::new()?; let path_prefix = config.path_prefix.clone(); let mailer = Arc::new(mailer::Mailer::new(&mut config)?); @@ -28,8 +26,7 @@ async fn init() -> Result<()> { .route("/success", get(routes::success)) .layer(Extension(config)) .layer(Extension(mailer)) - .layer(Extension(captcha_solutions)) - .layer(Extension(tera)); + .layer(Extension(captcha_solutions)); let app = Router::new().nest(&path_prefix, routes); diff --git a/src/routes.rs b/src/routes.rs index d9362c4..7bcd55b 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,30 +1,12 @@ use anyhow::{Context, Result}; +use askama_axum::IntoResponse; use axum::extract::{Extension, Form, Query}; -use axum::http::StatusCode; -use axum::response::{Html, IntoResponse, Response}; +use axum::response::Response; use serde::Deserialize; use std::mem; use std::sync::Arc; -use tera::Tera; -use crate::{captcha_solutions, config, context, forms, mailer}; - -pub struct AppError(anyhow::Error); - -impl IntoResponse for AppError { - fn into_response(self) -> Response { - StatusCode::BAD_REQUEST.into_response() - } -} - -impl From for AppError -where - E: Into, -{ - fn from(err: E) -> Self { - Self(err.into()) - } -} +use crate::{captcha_solutions, config, errors, forms, mailer, templates}; #[derive(Deserialize)] pub struct IndexParams { @@ -37,16 +19,15 @@ pub struct IndexParams { pub async fn index( Query(params): Query, - engine: Extension>, config: Extension>, captcha_solutions: Extension>, -) -> Result { +) -> Result { let captcha = captcha::by_name(captcha::Difficulty::Easy, captcha::CaptchaName::Lucy); let captcha_base64 = captcha.as_base64().context("Failed to create a captcha!")?; let id = captcha_solutions.store_solution(&captcha.chars_as_string()); - let form_context = context::ContactForm { + let template = templates::ContactForm { path_prefix: &config.path_prefix, was_validated: params.was_validated.unwrap_or(false), id, @@ -57,20 +38,14 @@ pub async fn index( captcha: &captcha_base64, }; - let html = engine.render( - "form.html.tera", - &tera::Context::from_serialize(&form_context)?, - )?; - - Ok(Html(html).into_response()) + Ok(template.into_response()) } async fn back_to_index( mut form: forms::ContactForm, - engine: Extension>, config: Extension>, captcha_solutions: Extension>, -) -> Result { +) -> Result { let name = mem::take(&mut form.name); let email = mem::take(&mut form.email); let telefon = mem::take(&mut form.telefon); @@ -84,32 +59,34 @@ async fn back_to_index( message: Some(message), }); - index(params, engine, config, captcha_solutions).await + index(params, config, captcha_solutions).await } pub async fn submit( Form(form): Form, - engine: Extension>, config: Extension>, captcha_solutions: Extension>, mailer: Extension>, -) -> Result { +) -> Result { if !captcha_solutions.check_answer(form.id, &form.captcha_answer) { - return back_to_index(form, engine, config, captcha_solutions).await; + return back_to_index(form, config, captcha_solutions).await; } match mailer.send(&form.name, &form.email, &form.telefon, &form.message) { Ok(_) => (), Err(_) => { - return back_to_index(form, engine, config, captcha_solutions).await; + return back_to_index(form, config, captcha_solutions).await; } } - success(engine).await + success().await } -pub async fn success(engine: Extension>) -> Result { - let html = engine.render("success.html.tera", &tera::Context::new())?; +pub async fn success() -> Result { + let template = templates::Success { + message: + "Ihre Anfrage wurde erfolgreich übermittelt! Wir melden uns bald bei Ihnen zurück.", + }; - Ok(Html(html).into_response()) + Ok(template.into_response()) } diff --git a/src/context.rs b/src/templates.rs similarity index 53% rename from src/context.rs rename to src/templates.rs index 5d581d2..5502a3c 100644 --- a/src/context.rs +++ b/src/templates.rs @@ -1,6 +1,7 @@ -use serde::Serialize; +use askama::Template; -#[derive(Serialize)] +#[derive(Template)] +#[template(path = "contact_form.askama.html")] pub struct ContactForm<'a> { pub path_prefix: &'a str, pub was_validated: bool, @@ -11,3 +12,9 @@ pub struct ContactForm<'a> { pub message: &'a str, pub captcha: &'a str, } + +#[derive(Template)] +#[template(path = "success.askama.html")] +pub struct Success<'a> { + pub message: &'a str, +} diff --git a/templates/base.html.tera b/templates/base.askama.html similarity index 100% rename from templates/base.html.tera rename to templates/base.askama.html diff --git a/templates/form.html.tera b/templates/contact_form.askama.html similarity index 98% rename from templates/form.html.tera rename to templates/contact_form.askama.html index 973505e..bb40df9 100644 --- a/templates/form.html.tera +++ b/templates/contact_form.askama.html @@ -1,4 +1,4 @@ -{% extends "base.html.tera" %} +{% extends "base.askama.html" %} {% block body %}

diff --git a/templates/success.askama.html b/templates/success.askama.html new file mode 100644 index 0000000..a1e644c --- /dev/null +++ b/templates/success.askama.html @@ -0,0 +1,7 @@ +{% extends "base.askama.html" %} + +{% block body %} +

+{% endblock %} diff --git a/templates/success.html.tera b/templates/success.html.tera deleted file mode 100644 index 850e383..0000000 --- a/templates/success.html.tera +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base.html.tera" %} - -{% block body %} - -{% endblock %}