diff --git a/src/api/health_form.rs b/src/api/health_form.rs index fedcde3..1bda2e7 100644 --- a/src/api/health_form.rs +++ b/src/api/health_form.rs @@ -2,457 +2,360 @@ use std::{collections::HashMap, fs}; use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; use actix_web::{post, HttpResponse}; +use color_eyre::{eyre::eyre, Result}; use lettre::{ message::{header::ContentType, Attachment, MultiPart, SinglePart}, Message, }; -use maud::{html, DOCTYPE}; -use reqwest::{Client, Error}; -use tracing::info; +use maud::{html, Markup, DOCTYPE}; +use reqwest::Client; +use tracing::{error, info}; use crate::email::send_email; -#[derive(Debug, MultipartForm, Default)] +#[derive(Debug, MultipartForm)] struct HealthForm { #[multipart(rename = "first-name")] - first_name: Option>, + first_name: Text, #[multipart(rename = "last-name")] - last_name: Option>, + last_name: Text, #[multipart(rename = "parent-first-name")] - parent_first_name: Option>, + parent_first_name: Text, #[multipart(rename = "parent-last-name")] - parent_last_name: Option>, + parent_last_name: Text, #[multipart(rename = "birth-date")] - birthdate: Option>, - street: Option>, - city: Option>, - state: Option>, - zip: Option>, + birthdate: Text, + street: Text, + city: Text, + state: Text, + zip: Text, #[multipart(rename = "cell-phone")] - parent_cellphone: Option>, + parent_cellphone: Text, #[multipart(rename = "home-phone")] - homephone: Option>, + homephone: Text, #[multipart(rename = "additional-emergency-contact")] - contact: Option>, + contact: Text, #[multipart(rename = "addtional-emergency-contact-phone")] - contact_phone: Option>, + contact_phone: Text, #[multipart(rename = "doctor-name")] - doctorname: Option>, + doctorname: Text, #[multipart(rename = "doctor-city")] - doctorcity: Option>, + doctorcity: Text, #[multipart(rename = "doctor-phone")] - doctorphone: Option>, + doctorphone: Text, #[multipart(rename = "medical-coverage")] - medical: Option>, + medical: Text, #[multipart(rename = "insurance-name")] - insurance: Option>, + insurance: Text, #[multipart(rename = "policy-number")] - policy_number: Option>, - allergies: Option>, + policy_number: Text, + allergies: Text, #[multipart(rename = "allergies-other")] - allergies_other: Option>, + allergies_other: Text, #[multipart(rename = "specific-allergies")] - specific_allergies: Option>, + specific_allergies: Text, #[multipart(rename = "allergic-treatment")] - treatment: Option>, - conditions: Option>, + treatment: Text, + conditions: Text, #[multipart(rename = "tetanus-shot")] - tetanus: Option>, + tetanus: Text, #[multipart(rename = "swimming-ability")] - swimming: Option>, + swimming: Text, #[multipart(rename = "medication-schedule")] - medication: Option>, + medication: Text, #[multipart(rename = "other-notes")] - notes: Option>, - agreement: Option>, + notes: Text, + agreement: Text, #[multipart(rename = "image")] file: Option, - registration: Option>, + registration: Text, } -#[post("/health-form")] -pub async fn health_form(MultipartForm(form): MultipartForm) -> HttpResponse { - 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 registration = form - .registration - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let email_subject = format!("{} {} filled out a health form!", first, last); - let filename_noext = format!("{}_{}", 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 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(String::from(""))) - .0 - .clone(); - let parent_cellphone = form - .parent_cellphone - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let homephone = form - .homephone - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let contact = form - .contact - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let contact_phone = form - .contact_phone - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let doctorname = form - .doctorname - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let doctorcity = form - .doctorcity - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let doctorphone = form - .doctorphone - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let medical = form - .medical - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let insurance = form - .insurance - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let policy_number = form - .policy_number - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let agreement = form - .agreement - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let allergies = form - .allergies - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let allergies_other = form - .allergies_other - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let specific_allergies = form - .specific_allergies - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let treatment = form - .treatment - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let conditions = form - .conditions - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let tetanus = form - .tetanus - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let swimming = form - .swimming - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let medication = form - .medication - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - let notes = form - .notes - .as_ref() - .unwrap_or(&Text(String::from(""))) - .0 - .clone(); - info!("{first} {last} filled out a health form!"); - let email = html! { - (DOCTYPE) - html { - head { - title { (first) " " (last) " filled out a health form!" } - 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 { "Health form for " (first) " " (last) "!" } - hr; - table { - tr { - th { "Name" } - td { (first) " " (last) } - } - tr { - th { "Parent" } - td { (parent) } - } - tr { - th { "Birthdate" } - td { (birthdate) } - } - tr { - th { "Street" } - td { (street) } - } - tr { - th { "City" } - td { (city) } - } - tr { - th { "State" } - td { (state) } - } - tr { - th { "Zip" } - td { (zip) } - } - tr { - th { "Phone" } - td { (parent_cellphone) } - } - tr { - th { "Home Phone" } - td { (homephone) } - } - tr { - th { "Additional Emergency Contact" } - td { (contact) } - } - tr { - th { "Contact Phone" } - td { (contact_phone) } - } - tr { - th { "Doctor" } - td { (doctorname) } - } - tr { - th { "Doctor City" } - td { (doctorcity) } - } - tr { - th { "Doctor Phone" } - td { (doctorphone) } - } - tr { - th { "Medical Coverage" } - td { (medical) } - } - tr { - th { "Insurance Provider" } - td { (insurance) } - } - tr { - th { "Policy Number" } - td { (policy_number) } - } - tr { - th { "Allergies" } - td { (allergies) } - } - tr { - th { "Other Allergies" } - td { (allergies_other) } - } - tr { - th { "Specific Allergies" } - td { (specific_allergies) } - } - tr { - th { "Treatments" } - td { (treatment) } - } - tr { - th { "Physical or mental conditions" } - td { (conditions) } - } - tr { - th { "Last tetanus shot" } - td { (tetanus) } - } - tr { - th { "Swimming Ability" } - td { (swimming) } - } - tr { - th { "Medication Schedule" } - td { (medication) } - } - tr { - th { "Other Relevant Info" } - td { (notes) } - } - tr { - th { "Final Agreement" } - td { (agreement) } - } - } - } - } - }; - let mut path: Option = Some(String::from("")); - let mut file_exists = false; - let mut filename = String::from(""); - info!("Does the file exist? {:?}", file_exists); +impl From<&HealthForm> for HashMap { + fn from(form: &HealthForm) -> Self { + let mut map = HashMap::new(); + map.insert(37, format!("{} {}", form.first_name.0, form.last_name.0)); + map.insert( + 38, + format!("{} {}", form.parent_first_name.0, form.parent_last_name.0), + ); + map.insert(39, form.birthdate.0.clone()); + map.insert(40, form.street.0.clone()); + map.insert(41, form.city.0.clone()); + map.insert(42, form.state.0.clone()); + map.insert(43, form.zip.0.clone()); + map.insert(44, form.parent_cellphone.0.clone()); + map.insert(45, form.homephone.0.clone()); + map.insert(46, format!("{} {}", form.contact.0, form.contact_phone.0)); + map.insert(47, form.doctorname.0.clone()); + map.insert(48, form.doctorcity.0.clone()); + map.insert(49, form.doctorphone.0.clone()); + map.insert(50, form.medical.0.clone()); + map.insert(51, form.insurance.0.clone()); + map.insert(52, form.policy_number.0.clone()); + map.insert(54, form.agreement.0.clone()); + map.insert( + 55, + format!("{} \n {}", form.allergies.0, form.allergies_other.0), + ); + map.insert(56, form.specific_allergies.0.clone()); + map.insert(57, form.treatment.0.clone()); + map.insert(58, form.conditions.0.clone()); + map.insert(59, form.tetanus.0.clone()); + map.insert(60, form.medication.0.clone()); + map.insert(61, form.notes.0.clone()); + map.insert(62, form.swimming.0.clone()); + map + } +} - match store_health_form(&form).await { - Ok(_) => info!("Successfully posted the health form in nextcloud tables"), - Err(e) => log::error!("Error posting health form to nextcloud tables: {:?}", e), +impl HealthForm { + async fn build_email(&self) -> Markup { + html! { + (DOCTYPE) + meta charset="utf-8"; + html { + head { + title { (self.first_name.0) " " (self.last_name.0) " filled out a health form!" } + 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 { "Health form for " (self.first_name.0) " " (self.last_name.0) "!" } + hr; + table { + tr { + th { "Name" } + td { (self.first_name.0) " " (self.last_name.0) } + } + tr { + th { "Parent" } + td { (self.parent_first_name.0) " " (self.parent_last_name.0) } + } + tr { + th { "Birthdate" } + td { (self.birthdate.0) } + } + tr { + th { "Street" } + td { (self.street.0) } + } + tr { + th { "City" } + td { (self.city.0) } + } + tr { + th { "State" } + td { (self.state.0) } + } + tr { + th { "Zip" } + td { (self.zip.0) } + } + tr { + th { "Parent Cell Phone" } + td { (self.parent_cellphone.0) } + } + tr { + th { "Homephone" } + td { (self.homephone.0) } + } + tr { + th { "Additional Emergency Contact" } + td { (self.contact.0) } + } + tr { + th { "Emegency Contact Phone" } + td { (self.contact_phone.0) } + } + tr { + th { "Doctor" } + td { (self.doctorname.0) } + } + tr { + th { "Doctor City" } + td { (self.doctorcity.0) } + } + tr { + th { "Doctor Phone" } + td { (self.doctorphone.0) } + } + tr { + th { "Medical Coverage" } + td { (self.medical.0) } + } + tr { + th { "Insurance Provider" } + td { (self.insurance.0) } + } + tr { + th { "Policy Number" } + td { (self.policy_number.0) } + } + tr { + th { "Allergies" } + td { (self.allergies.0) + "\n\n" + (self.allergies_other.0) + } + } + tr { + th { "Specific Allergies" } + td { (self.specific_allergies.0) } + } + tr { + th { "Allergic Treatments" } + td { (self.treatment.0) } + } + tr { + th { "Conditions" } + td { (self.conditions.0) } + } + tr { + th { "Date of last Tetanus Shot" } + td { (self.tetanus.0) } + } + tr { + th { "Swimming Ability" } + td { (self.swimming.0) } + } + tr { + th { "Medication Schedule" } + td { (self.medication.0) } + } + tr { + th { "Other Notes" } + td { (self.notes.0) } + } + tr { + th { "Final Agreement" } + td { (self.agreement.0) } + } + tr { + th { "Registration" } + td { (self.registration.0) } + } + } + } + } + } } - if let Some(f) = form.file { - if let Some(file) = f.file_name { - if let Some(ext) = file.rsplit('.').next() { + async fn store_form(&self) -> Result<()> { + let client = Client::new(); + let map = HashMap::from(self); + let mut json = HashMap::new(); + json.insert("data", map); + + let link = r#"https://staff.tfcconnection.org/apps/tables/#/table/4/row/757"#; + let res = client + .post("https://staff.tfcconnection.org/ocs/v2.php/apps/tables/api/2/tables/4/rows") + .basic_auth("chris", Some("2VHeGxeC^Zf9KqFK^G@Pt!zu2q^6@b")) + .header("OCS-APIRequest", "true") + .header("Content-Type", "application/json") + .json(&json) + .send() + .await?; + if res.status().is_success() { + let res = res.text().await.unwrap(); + Ok(()) + } else { + Err(eyre!( + "Problem in storing data: {:?}", + res.error_for_status() + )) + } + } + + fn get_temp_file(&mut self) -> Option<(String, String)> { + let first = self.first_name.clone(); + let last = self.last_name.clone(); + let filename_noext = format!("{}_{}", first, last); + let file_name = if let Some(file) = self.file.as_ref() { + file.file_name.to_owned() + } else { + return None; + }; + let filename; + let path = if let Some(file_name) = file_name { + if let Some(ext) = file_name.rsplit('.').next() { filename = format!("{}.{}", filename_noext, ext); - path = Some(format!("./tmp/{}.{}", filename_noext, ext)); + format!("./tmp/{}.{}", filename_noext, ext) } else { - path = Some(format!("./tmp/{}", file)); + filename = String::default(); + format!("./tmp/{}", file_name) } - // let path = format!("./tmp/{}", file); - info!("saving to {}", path.clone().unwrap()); - match f.file.persist(path.clone().unwrap()) { - Ok(f) => { - info!( - "Hey! We got a file! {:?}", - f.metadata().expect("Something bad happened mate") - ); - if f.metadata().unwrap().len() > 0 { - file_exists = true; - } + } else { + filename = String::default(); + String::default() + }; + let file = self.file.take(); + match file.unwrap().file.persist(path.clone()) { + Ok(f) => { + if f.metadata().unwrap().len() <= 0 { + return None; } - Err(e) => info!("{:?}: Probably a missing image", e), + info!(?f, "File saved successfully"); + Some((filename, path)) + } + Err(e) => { + error!("{:?}: Probably a missing image", e); + None } } } - let multi = if file_exists { - let filebody = fs::read(path.clone().unwrap_or_default()); - let content_type = ContentType::parse("image/jpg").unwrap(); - let attachment = Attachment::new(filename).body(filebody.unwrap(), content_type); - // info!("The attachment is: {:?}", attachment.headers()); - MultiPart::mixed() - .singlepart(SinglePart::html(email.into_string())) - .singlepart(attachment) - } else { - MultiPart::alternative_plain_html(String::from("Testing"), email.into_string()) - }; + async fn send_email(&mut self) -> Result<()> { + let first = self.first_name.clone(); + let last = self.last_name.clone(); + let email_subject = format!("{} {} signed up for mission trip!", first, last); + info!("{first} {last} signed up for mission trip!"); + let email = self.build_email().await; + let temp_file = self.get_temp_file(); + let multi = if let Some((file, path)) = temp_file { + let filebody = fs::read(path); + let content_type = ContentType::parse("image/jpg").unwrap(); + let attachment = Attachment::new(file).body(filebody.unwrap(), content_type); + // info!(?attachment); + MultiPart::mixed() + .singlepart(SinglePart::html(email.into_string())) + .singlepart(attachment) + } else { + MultiPart::alternative_plain_html(String::from("Testing"), email.into_string()) + }; - // info!("{:?}", multi); + if let Ok(m) = Message::builder() + .from( + "TFC ADMIN " + .parse() + .unwrap(), + ) + .to("Chris Cochrun ".parse().unwrap()) + .subject(email_subject) + .multipart(multi) + { + crate::email::send_email(m).await + } else { + Err(eyre!("Email incorrect")) + } + } +} - 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"); +#[post("/health-form")] +pub async fn health_form(MultipartForm(mut form): MultipartForm) -> HttpResponse { + match form.send_email().await { + Ok(_) => info!("Successfully sent email health form"), + Err(e) => error!("There was an error sending email: {e}"), } - match registration.as_str() { + let full_name = format!("{} {}", form.first_name.0, form.last_name.0); + match form.registration.0.as_str() { "now" => { info!("Sending them to pay for registration now"); HttpResponse::Ok() @@ -492,7 +395,7 @@ pub async fn health_form(MultipartForm(form): MultipartForm) -> Http _ => { log::error!( "Got registration error possibly. Here is what the registration was: {}", - registration.as_str() + form.registration.0.as_str() ); let html = html! { div class="mt-8" { @@ -511,241 +414,3 @@ pub async fn health_form(MultipartForm(form): MultipartForm) -> Http } // HttpResponse::Ok().body("hi") } - -async fn store_health_form(form: &HealthForm) -> Result<(), Error> { - let request = Client::new(); - let mut map = HashMap::new(); - map.insert( - 37, - format!( - "{} {}", - form.first_name - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - form.last_name - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone() - ), - ); - map.insert( - 38, - format!( - "{} {}", - form.parent_first_name - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - form.parent_last_name - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone() - ), - ); - map.insert( - 39, - form.birthdate - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 40, - form.street - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 41, - form.city.as_ref().unwrap_or(&Text(String::new())).0.clone(), - ); - map.insert( - 42, - form.state - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 43, - form.zip.as_ref().unwrap_or(&Text(String::new())).0.clone(), - ); - map.insert( - 44, - form.parent_cellphone - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 45, - form.homephone - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 46, - format!( - "{} {}", - form.contact - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - form.contact_phone - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ), - ); - map.insert( - 47, - form.doctorname - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 48, - form.doctorcity - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 49, - form.doctorphone - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 50, - form.medical - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 51, - form.insurance - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 52, - form.policy_number - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 54, - form.agreement - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 55, - format!( - "{}{}", - form.allergies - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - form.allergies_other - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ), - ); - map.insert( - 56, - form.specific_allergies - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 57, - form.treatment - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 58, - form.conditions - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 59, - form.tetanus - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 62, - form.swimming - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 60, - form.medication - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - map.insert( - 61, - form.notes - .as_ref() - .unwrap_or(&Text(String::new())) - .0 - .clone(), - ); - let mut json = HashMap::new(); - json.insert("data", map); - request - .post("https://staff.tfcconnection.org/apps/tables/api/1/tables/4/rows") - .basic_auth("chris", Some("2VHeGxeC^Zf9KqFK^G@Pt!zu2q^6@b")) - .json(&json) - .send() - .await?; - Ok(()) -} diff --git a/src/api/mt_form.rs b/src/api/mt_form.rs index e339cdb..6a8ca26 100644 --- a/src/api/mt_form.rs +++ b/src/api/mt_form.rs @@ -1,19 +1,14 @@ -use std::{ - collections::{BTreeMap, HashMap}, - fs, -}; +use std::{collections::HashMap, fs}; use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; -use actix_web::{post, web, HttpResponse}; +use actix_web::{post, HttpResponse}; use color_eyre::{eyre::eyre, Result}; use lettre::{ message::{header::ContentType, Attachment, MultiPart, SinglePart}, Message, }; -use maud::{html, Markup, PreEscaped, DOCTYPE}; +use maud::{html, Markup, DOCTYPE}; use reqwest::Client; -use serde_json::json; -use sqlx::SqliteConnection; use tracing::{error, info}; #[derive(Debug, MultipartForm)]