diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d52e004 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,12 @@ +mod routes; +mod states; + +use rocket_dyn_templates::Template; + +#[rocket::launch] +fn rocket() -> _ { + rocket::build() + .mount("/", rocket::routes![routes::index, routes::submit]) + .manage(states::SharedCaptchaSolutions::new()) + .attach(Template::fairing()) +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..47253c9 --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,56 @@ +use rocket::form::{Form, FromForm, Strict}; +use rocket::response::status::BadRequest; +use rocket::{get, post, State}; +use rocket_dyn_templates::Template; +use serde::Serialize; + +use crate::states; + +#[derive(Serialize)] +struct FormContext { + id: u16, + captcha: String, +} + +#[get("/")] +pub fn index( + captcha_solutions: &State, +) -> Result> { + let captcha = captcha::by_name(captcha::Difficulty::Easy, captcha::CaptchaName::Lucy); + let captcha_base64 = match captcha.as_base64() { + Some(s) => s, + None => return Err(BadRequest(None)), + }; + + let id = captcha_solutions.store_solution(&captcha.chars_as_string()); + + let form_context = FormContext { + id, + captcha: captcha_base64, + }; + + Ok(Template::render("form", &form_context)) +} + +#[derive(FromForm)] +pub struct ContactForm { + id: u16, + name: String, + email: String, + telefon: String, + message: String, + captcha_answer: String, +} + +#[post("/submit", data = "
")] +pub fn submit( + form: Form>, + captcha_solutions: &State, +) -> Result> { + println!( + "{}", + captcha_solutions.check_answer(form.id, &form.captcha_answer) + ); + + Ok("Ihre Anfrage wurde übermittelt. Wir melden uns bald bei Ihnen zurück.".to_string()) +} diff --git a/src/states.rs b/src/states.rs new file mode 100644 index 0000000..d2f66e7 --- /dev/null +++ b/src/states.rs @@ -0,0 +1,49 @@ +use std::sync::{Arc, Mutex}; + +pub struct CaptchaSolutions { + last_id: u16, + solutions: Vec>, +} + +pub struct SharedCaptchaSolutions { + arc: Arc>, +} + +impl SharedCaptchaSolutions { + pub fn new() -> Self { + let max_size = (u16::MAX as usize) + 1; + let mut solutions = Vec::with_capacity(max_size); + solutions.resize(max_size, None); + + Self { + arc: Arc::new(Mutex::new(CaptchaSolutions { + last_id: 0, + solutions, + })), + } + } + + pub fn store_solution(&self, solution: &str) -> u16 { + let mut captcha_solutions = self.arc.lock().unwrap(); + + let new_id = captcha_solutions.last_id.wrapping_add(1); + captcha_solutions.last_id = new_id; + + captcha_solutions.solutions[new_id as usize] = Some(solution.to_string()); + + new_id + } + + pub fn check_answer(&self, id: u16, answer: &str) -> bool { + let mut captcha_solutions = self.arc.lock().unwrap(); + + let id = id as usize; + + if captcha_solutions.solutions[id] == Some(answer.trim().to_string()) { + captcha_solutions.solutions[id] = None; + return true; + } + + false + } +} diff --git a/templates/form.html.tera b/templates/form.html.tera new file mode 100644 index 0000000..224853b --- /dev/null +++ b/templates/form.html.tera @@ -0,0 +1,40 @@ + + + + + + Contact form + + +

Kontakt-Formular

+ + + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + + + + +