use std::collections::HashMap; use actix_multipart::form::{text::Text, MultipartForm}; use actix_web::{http::StatusCode, post, HttpResponse, HttpResponseBuilder}; use lettre::{ message::MultiPart, transport::smtp::authentication::{Credentials, Mechanism}, Message, SmtpTransport, Transport, }; use maud::html; use maud::DOCTYPE; use reqwest::{Client, Error}; use tracing::info; use crate::email::send_email; #[derive(Debug, MultipartForm, Default)] struct CampForm { #[multipart(rename = "first-name")] first_name: Option>, #[multipart(rename = "last-name")] last_name: Option>, #[multipart(rename = "parent-first-name")] parent_first_name: Option>, #[multipart(rename = "parent-last-name")] parent_last_name: Option>, #[multipart(rename = "birth-date")] birthdate: Option>, gender: Option>, street: Option>, city: Option>, state: Option>, zip: Option>, #[multipart(rename = "parent-phone")] parent_phone: Option>, #[multipart(rename = "parent-email")] parent_email: Option>, grade: Option>, shirt: Option>, allergies: Option>, week: Option>, registration: Option>, #[multipart(rename = "health-form")] health_form: Option>, } #[post("/camp-form")] pub async fn camp_form(MultipartForm(form): MultipartForm) -> HttpResponse { info!("a new form"); let first = form .first_name .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let last = form .last_name .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let full_name = format!("{} {}", first, last); let email_subject = format!("{} {} signed up for camp!", first, last); let parent = format!( "{} {}", form.parent_first_name .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(), form.parent_last_name .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone() ); let birthdate = form .birthdate .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let gender = form .gender .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let street = form .street .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let city = form .city .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let state = form .state .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let zip = form.zip.as_ref().unwrap_or(&Text(0)).0; let parent_phone = form .parent_phone .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let parent_email = form .parent_email .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let grade = form .grade .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let shirt = form .shirt .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let allergies = form .allergies .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let week = form .week .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let registration = form .registration .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let health = form .health_form .as_ref() .unwrap_or(&Text(String::from(""))) .0 .clone(); let reg = registration.clone(); info!("Sending post to database"); info!("{first} {last} signed up for camp!"); let email = html! { (DOCTYPE) meta charset="utf-8"; html { head { title { (first) " " (last) " signed up for camp!" } style { "table { border-collapse: collapse; width: 100% }" "td, th { padding: 8px }" "td { text-align: left; width: 70%; word-wrap: break-word }" "th { text-align: right; border-right: 1px solid #ddd }" "tr { border-bottom: 1px solid #ddd }" "h1 { text-align: center }" } } body { h1 { "Camp form for " (first) " " (last) } hr; table { tr { th { "Name" } td { (first) " " (last) } } tr { th { "Parent" } td { (parent) } } tr { th { "Birthdate" } td { (birthdate) } } tr { th { "Gender" } td { (gender) } } tr { th { "Street" } td { (street) } } tr { th { "City" } td { (city) } } tr { th { "State" } td { (state) } } tr { th { "Zip" } td { (zip) } } tr { th { "Parent Phone" } td { (parent_phone) } } tr { th { "Parent Email" } td { (parent_email) } } tr { th { "Grade" } td { (grade) } } tr { th { "Camper Allergies" } td { (allergies) } } tr { th { "T-Shirt Size" } td { (shirt) } } tr { th { "Week Choice" } td { (week) } } tr { th { "Health Form" } td { (health) } } tr { th { "Registration" } td { (registration) } } } } } }; let multi = MultiPart::alternative_plain_html( String::from("A camp form was filled out!"), email.into_string(), ); if let Ok(m) = Message::builder() .from( "TFC ADMIN " .parse() .unwrap(), ) .to("Chris Cochrun ".parse().unwrap()) .to("Ethan Rose ".parse().unwrap()) .subject(email_subject) .multipart(multi) { let _ = send_email(m); } else { info!("Email incorrect"); } match store_camp_form(form).await { Ok(_) => info!("Successfully posted to nextcloud tables"), Err(e) => log::error!("Error in posting camp data: {:?}", e), } match health.as_str() { "now" => { info!("Sending them to fill out the health form"); HttpResponse::Ok() .insert_header(("Access-Control-Expose-Headers", "*")) .insert_header(( "HX-Redirect", format!( "https://tfcconnection.org/camp-health-form/?registration={}", reg.as_str() ), )) .finish() } "later" => match reg.as_str() { "now" => { info!("Sending them to pay for registration now"); HttpResponse::Ok() .insert_header(("Access-Control-Expose-Headers", "*")) .insert_header(( "HX-Redirect", "https://secure.myvanco.com/L-Z772/campaign/C-13JPJ", )) .finish() } "full" => { info!("Sending them to pay for the full registration now"); HttpResponse::Ok() .insert_header(("Access-Control-Expose-Headers", "*")) .insert_header(( "HX-Redirect", "https://secure.myvanco.com/L-Z772/campaign/C-13JQE", )) .finish() } "later" => { info!("{} would like to pay later", full_name); let html = html! { div class="mt-8" { h2 { "Thank you, " (full_name) "!" } p { "Can't wait to see you at camp!" } p { class { "" } "If you'd like to pay for your registration go to the donate tab in the top right when you are ready and find the camp registration option." } } }; HttpResponse::Ok().body(html.into_string()) } _ => { log::error!("Got registration error....."); let html = html! { div class="mt-8" { h2 { "Thank you, " (full_name) "!" } p { "Can't wait to see you at camp!" } p { class { "" } "If you'd like to pay for your registration go to the donate tab in the top right when you are ready and find the camp registration option." } } }; HttpResponse::Ok().body(html.into_string()) } }, _ => { log::error!("Unknown selection for health. We don't know where to send the user."); HttpResponseBuilder::new(StatusCode::IM_A_TEAPOT) .body("Unknown selection for health. We don't know where to send the user.") } } } async fn store_camp_form(form: CampForm) -> Result<(), Error> { let request = Client::new(); let mut map = HashMap::new(); map.insert( 63, format!( "{} {}", &form.first_name.unwrap_or(Text(String::new())).0, &form.last_name.unwrap_or(Text(String::new())).0 ), ); map.insert( 64, format!( "{} {}", form.parent_first_name.unwrap_or(Text(String::new())).0, form.parent_last_name.unwrap_or(Text(String::new())).0 ), ); map.insert(65, form.parent_phone.unwrap_or(Text(String::new())).0); map.insert(66, form.parent_email.unwrap_or(Text(String::new())).0); map.insert(67, form.birthdate.unwrap_or(Text(String::new())).0); map.insert(69, form.gender.unwrap_or(Text(String::new())).0); map.insert(70, form.street.unwrap_or(Text(String::new())).0); map.insert(71, form.city.unwrap_or(Text(String::new())).0); map.insert(72, form.state.unwrap_or(Text(String::new())).0); map.insert(73, form.zip.unwrap_or(Text(0)).0.to_string()); map.insert(74, form.grade.unwrap_or(Text(String::new())).0); map.insert(75, form.week.unwrap_or(Text(String::new())).0); map.insert(76, form.shirt.unwrap_or(Text(String::new())).0); map.insert(77, form.registration.unwrap_or(Text(String::new())).0); map.insert(115, form.health_form.unwrap_or(Text(String::new())).0); let mut json = HashMap::new(); json.insert("data", map); request .post("https://staff.tfcconnection.org/apps/tables/api/1/tables/5/rows") // .header("xc-token", "Ohah24HNGXVvvixv8tvVJW5uNNdWjDJHG1d4t3o9") .basic_auth("chris", Some("2VHeGxeC^Zf9KqFK^G@Pt!zu2q^6@b")) .json(&json) .send() .await?; Ok(()) }