getting more forms ready for mt-forms
This commit is contained in:
parent
e934788259
commit
6603d2c6bc
|
@ -8,52 +8,52 @@ sharingLinks: false
|
||||||
|
|
||||||
Mission Trip applications are closed until next year.
|
Mission Trip applications are closed until next year.
|
||||||
|
|
||||||
<!-- If you are looking for the reference forms they are here, [parent](/mt-parent-form), [teacher](/mt-teacher-form), and [church-related](/mt-church-form)! Please click the appropriate one for them! Here is the [health form](/mt-health-form)! Also, if you need to pay please go [here](/donate). Thank you! -->
|
If you are looking for the reference forms they are here, [parent](/mt-parent-form), [teacher](/mt-teacher-form), and [church-related](/mt-church-form)! Please click the appropriate one for them! Here is the [health form](/mt-health-form)! Also, if you need to pay please go [here](/donate). Thank you!
|
||||||
|
|
||||||
<!-- ## Mission Trip Options -->
|
## Mission Trip Options
|
||||||
<!-- This year we have three options for mission trip! -->
|
This year we have three options for mission trip!
|
||||||
|
|
||||||
<!-- ## Gallup, New Mexico - May 29 - June 10 - 8th Grade and above -->
|
## Gallup, New Mexico - May 29 - June 10 - 8th Grade and above
|
||||||
<!-- This trip is designed for students who are ready for the challenge of leaving their personal desires behind as they follow Jesus and help meet the needs of others. This southwestern experience will find us making our home base at the 117-year-old campus of Rehoboth Christian school, where we will work with and serve the people in the community, making a difference in the lives of a variety of people. -->
|
This trip is designed for students who are ready for the challenge of leaving their personal desires behind as they follow Jesus and help meet the needs of others. This southwestern experience will find us making our home base at the 117-year-old campus of Rehoboth Christian school, where we will work with and serve the people in the community, making a difference in the lives of a variety of people.
|
||||||
|
|
||||||
<!-- As a part of the Destination Rehoboth experience, we will volunteer at various locations in meaningful service projects both on and off of Rehoboth’s campus. Off-campus opportunities might include helping at the local food shelter, assisting Rehoboth families in need with home repair projects, or serving at churches on the reservation. Campus needs might include painting and minor repairs, or landscaping. -->
|
As a part of the Destination Rehoboth experience, we will volunteer at various locations in meaningful service projects both on and off of Rehoboth’s campus. Off-campus opportunities might include helping at the local food shelter, assisting Rehoboth families in need with home repair projects, or serving at churches on the reservation. Campus needs might include painting and minor repairs, or landscaping.
|
||||||
|
|
||||||
<!-- Requirements for this team are a flexible attitude and a willingness to do hands-on labor. For more information about RCS and their current projects, check out their [website](https://www.rcsnm.org) and their [Facebook page](https://www.facebook.com/rcsnm). -->
|
Requirements for this team are a flexible attitude and a willingness to do hands-on labor. For more information about RCS and their current projects, check out their [website](https://www.rcsnm.org) and their [Facebook page](https://www.facebook.com/rcsnm).
|
||||||
|
|
||||||
<!-- - Estimated Support Goal of $850-$950 -->
|
- Estimated Support Goal of $850-$950
|
||||||
|
|
||||||
<!-- ## Puerto Escondido, Mexico - *June 2 - 9 - Highschool only -->
|
## Puerto Escondido, Mexico - *June 2 - 9 - Highschool only
|
||||||
<!-- This trip is designed for students who have a desire to be used by Jesus to draw others into a relationship with Him and they will be trained to go with the Gospel as His ambassadors. We will be working with the ministry of Roca Blanca Mission Base in Puerto Escondido, Mexico. There are a variety of ways to serve this ministry, we might lead a VBS, work in their orphanage, assist with village ministry, work on building projects, or possibly help deliver food or clothing. -->
|
This trip is designed for students who have a desire to be used by Jesus to draw others into a relationship with Him and they will be trained to go with the Gospel as His ambassadors. We will be working with the ministry of Roca Blanca Mission Base in Puerto Escondido, Mexico. There are a variety of ways to serve this ministry, we might lead a VBS, work in their orphanage, assist with village ministry, work on building projects, or possibly help deliver food or clothing.
|
||||||
|
|
||||||
<!-- Requirements for this team are a willingness and desire to share the gospel of Jesus verbally, -->
|
Requirements for this team are a willingness and desire to share the gospel of Jesus verbally,
|
||||||
<!-- relationally, and through physical work. Here is more information about [Roca Blanca](https://rocablanca.org). -->
|
relationally, and through physical work. Here is more information about [Roca Blanca](https://rocablanca.org).
|
||||||
|
|
||||||
<!-- - Estimated Support Goal of $1900-$2100 -->
|
- Estimated Support Goal of $1900-$2100
|
||||||
|
|
||||||
<!-- > You must have a passport for this trip. This will be an approximate $135 (including photo fee) additional personal expense. Allow for 6-8 weeks or pay an additional $60 for 2-3 week turn around. -->
|
> You must have a passport for this trip. This will be an approximate $135 (including photo fee) additional personal expense. Allow for 6-8 weeks or pay an additional $60 for 2-3 week turn around.
|
||||||
|
|
||||||
<!-- > \* Dates may vary slightly due to flight schedules -->
|
> \* Dates may vary slightly due to flight schedules
|
||||||
|
|
||||||
<!-- ### Mexico Travel Info -->
|
### Mexico Travel Info
|
||||||
<!-- The Roca Blanca Mission Base is located in the safest and most secure area of Mexico, according to the US State Department, well and easily patrolled, virtually free from the drug and other violence issues that are plaguing the border towns and Mexico’s large cities. For more detailed official US State Department information [click here.](https://travel.state.gov/content/travel/en/traveladvisories/traveladvisories/mexico-travel-advisory.html) After a series of general warnings for Mexico they have a state by state listing. For reference, we’re located in the State of Oaxaca where there are no travel warnings in effect. -->
|
The Roca Blanca Mission Base is located in the safest and most secure area of Mexico, according to the US State Department, well and easily patrolled, virtually free from the drug and other violence issues that are plaguing the border towns and Mexico’s large cities. For more detailed official US State Department information [click here.](https://travel.state.gov/content/travel/en/traveladvisories/traveladvisories/mexico-travel-advisory.html) After a series of general warnings for Mexico they have a state by state listing. For reference, we’re located in the State of Oaxaca where there are no travel warnings in effect.
|
||||||
|
|
||||||
<!-- With the same common sense precautions that you would take traveling anywhere, our coastal area is still the safe place to visit that it has been for many decades, safer than visiting many US cities. -->
|
With the same common sense precautions that you would take traveling anywhere, our coastal area is still the safe place to visit that it has been for many decades, safer than visiting many US cities.
|
||||||
|
|
||||||
<!-- It’s easy to forget just how big Mexico is, and how far our location is from the warning areas! If you visit us, in most cases your flight will arrive directly to Huatulco (HUX), or by means of the Mexico City airport to Puerto Escondido (PXM), these being our nearest international airports. There we meet you at the airport and drive you here. You’re not within a thousand miles of a border town or hundreds of miles from a city with a warning. We also begin your stay here with an orientation, which includes safety tips to avoid any danger that might present itself. We live here and we raise our children here. You can trust our record of many years of safety for visitors and students. -->
|
It’s easy to forget just how big Mexico is, and how far our location is from the warning areas! If you visit us, in most cases your flight will arrive directly to Huatulco (HUX), or by means of the Mexico City airport to Puerto Escondido (PXM), these being our nearest international airports. There we meet you at the airport and drive you here. You’re not within a thousand miles of a border town or hundreds of miles from a city with a warning. We also begin your stay here with an orientation, which includes safety tips to avoid any danger that might present itself. We live here and we raise our children here. You can trust our record of many years of safety for visitors and students.
|
||||||
|
|
||||||
<!-- ## 1-2 Day Local Trip - TBD -->
|
## 1-2 Day Local Trip - TBD
|
||||||
<!-- Formerly known as the SPLASH trip, this trip will be within 2 hours of the TFC office in Phillipsburg, KS and will be a 2 day trip where you can get a taste for a longer mission trip. If you don’t feel ready to go on a longer trip, or have scheduling conflicts with the other trips, this is the trip for you! You will still have the opportunity to serve and grow in your faith in Jesus. Click the button below to sign up for this trip! -->
|
Formerly known as the SPLASH trip, this trip will be within 2 hours of the TFC office in Phillipsburg, KS and will be a 2 day trip where you can get a taste for a longer mission trip. If you don’t feel ready to go on a longer trip, or have scheduling conflicts with the other trips, this is the trip for you! You will still have the opportunity to serve and grow in your faith in Jesus. Click the button below to sign up for this trip!
|
||||||
|
|
||||||
<!-- {{< button href="/local-trip-form">}} -->
|
{{< button href="/local-trip-form">}}
|
||||||
<!-- Local Trip -->
|
Local Trip
|
||||||
<!-- {{< /button >}} -->
|
{{< /button >}}
|
||||||
|
|
||||||
<!-- ## Mission Trip Agreement -->
|
## Mission Trip Agreement
|
||||||
<!-- > In order to fill out the application, you must agree to the following! -->
|
> In order to fill out the application, you must agree to the following!
|
||||||
|
|
||||||
<!-- - I agree to obey all rules and guidelines that TFC Connection and other associated ministries establish, realizing they have my best interest and welfare in mind. I will trust their judgment and obey them. **The staff have the right to confront me if they see a problem in my attitude or in my obeying the rules.** -->
|
- I agree to obey all rules and guidelines that TFC Connection and other associated ministries establish, realizing they have my best interest and welfare in mind. I will trust their judgment and obey them. **The staff have the right to confront me if they see a problem in my attitude or in my obeying the rules.**
|
||||||
<!-- - I agree to participate in the support raising part of this project. Even though I may have the finances to pay my own way, I will send out a _**minimum of 10 letters**_ to people who would be interested in this project. **I will also respect the deadlines to get my letters in the mail and realize this may lead to my dismissal from a trip if I haven’t done my part.** -->
|
- I agree to participate in the support raising part of this project. Even though I may have the finances to pay my own way, I will send out a _**minimum of 10 letters**_ to people who would be interested in this project. **I will also respect the deadlines to get my letters in the mail and realize this may lead to my dismissal from a trip if I haven’t done my part.**
|
||||||
<!-- - I acknowledge that I am expected to do my share of the work on the mission trip and I will be willing to do what is asked of me with an "I'd be glad to" attitude. -->
|
- I acknowledge that I am expected to do my share of the work on the mission trip and I will be willing to do what is asked of me with an "I'd be glad to" attitude.
|
||||||
<!-- - **I will work at making this mission trip a priority!** even if other events come up after I am accepted on a mission trip, I will commit to still go on this trip. -->
|
- **I will work at making this mission trip a priority!** even if other events come up after I am accepted on a mission trip, I will commit to still go on this trip.
|
||||||
|
|
||||||
{{< mt-form >}}
|
{{< mt-form >}}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
placeholder="Last Name" class="flex-1 form-input {{ $formClasses }}">
|
placeholder="Last Name" class="flex-1 form-input {{ $formClasses }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="basis-full flex flex-wrap my-4">
|
<div class="basis-full flex flex-wrap my-4">
|
||||||
<label for="studentnfirstname" class="basis-full">Teenager's first and last name?</label>
|
<label for="studentfirstname" class="basis-full">Teenager's first and last name?</label>
|
||||||
<input type="text" id="studentfirstname" name="studentfirstname"
|
<input type="text" id="studentfirstname" name="studentfirstname"
|
||||||
class="flex-1 form-input {{ $formClasses }}"
|
class="flex-1 form-input {{ $formClasses }}"
|
||||||
placeholder="First Name">
|
placeholder="First Name">
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
placeholder="Last Name" class="flex-1 form-input {{ $formClasses }}">
|
placeholder="Last Name" class="flex-1 form-input {{ $formClasses }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="basis-full flex flex-wrap my-4">
|
<div class="basis-full flex flex-wrap my-4">
|
||||||
<label for="studentnfirstname" class="basis-full">Teenager's first and last name?</label>
|
<label for="studentfirstname" class="basis-full">Teenager's first and last name?</label>
|
||||||
<input type="text" id="studentfirstname" name="studentfirstname"
|
<input type="text" id="studentfirstname" name="studentfirstname"
|
||||||
class="flex-1 form-input {{ $formClasses }}"
|
class="flex-1 form-input {{ $formClasses }}"
|
||||||
placeholder="First Name">
|
placeholder="First Name">
|
||||||
|
|
|
@ -3,6 +3,9 @@ pub mod church_form;
|
||||||
// pub mod errors;
|
// pub mod errors;
|
||||||
pub mod health_form;
|
pub mod health_form;
|
||||||
pub mod local_trip_form;
|
pub mod local_trip_form;
|
||||||
|
pub mod mt_church_form;
|
||||||
pub mod mt_form;
|
pub mod mt_form;
|
||||||
|
pub mod mt_parent_form;
|
||||||
|
pub mod mt_teacher_form;
|
||||||
pub mod parent_form;
|
pub mod parent_form;
|
||||||
pub mod teacher_form;
|
pub mod teacher_form;
|
||||||
|
|
233
src/api/mt_church_form.rs
Normal file
233
src/api/mt_church_form.rs
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
fs,
|
||||||
|
};
|
||||||
|
|
||||||
|
use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
|
||||||
|
use actix_web::{post, web, HttpResponse};
|
||||||
|
use color_eyre::{eyre::eyre, Result};
|
||||||
|
use lettre::{
|
||||||
|
message::{header::ContentType, Attachment, MultiPart, SinglePart},
|
||||||
|
Message,
|
||||||
|
};
|
||||||
|
use maud::{html, Markup, PreEscaped, DOCTYPE};
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde_json::json;
|
||||||
|
use sqlx::SqliteConnection;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
#[derive(Debug, MultipartForm)]
|
||||||
|
struct MtChurchForm {
|
||||||
|
#[multipart(rename = "firstname")]
|
||||||
|
first_name: Text<String>,
|
||||||
|
#[multipart(rename = "lastname")]
|
||||||
|
last_name: Text<String>,
|
||||||
|
#[multipart(rename = "studentfirstname")]
|
||||||
|
student_first_name: Text<String>,
|
||||||
|
#[multipart(rename = "studentlastname")]
|
||||||
|
student_last_name: Text<String>,
|
||||||
|
relationship: Text<String>,
|
||||||
|
#[multipart(rename = "walk-with-jesus")]
|
||||||
|
walk_jesus: Text<String>,
|
||||||
|
commitment: Text<String>,
|
||||||
|
#[multipart(rename = "pos-characteristics")]
|
||||||
|
positive: Text<String>,
|
||||||
|
#[multipart(rename = "neg-characteristics")]
|
||||||
|
negative: Text<String>,
|
||||||
|
teachable: Text<String>,
|
||||||
|
#[multipart(rename = "extra-info")]
|
||||||
|
extra_info: Text<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&MtChurchForm> for HashMap<i32, String> {
|
||||||
|
fn from(form: &MtChurchForm) -> Self {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(158, format!("{} {}", form.first_name.0, form.last_name.0));
|
||||||
|
map.insert(
|
||||||
|
159,
|
||||||
|
format!("{} {}", form.student_first_name.0, form.student_last_name.0),
|
||||||
|
);
|
||||||
|
map.insert(160, form.relationship.0.clone());
|
||||||
|
map.insert(163, form.positive.0.clone());
|
||||||
|
map.insert(164, form.negative.0.clone());
|
||||||
|
map.insert(161, form.walk_jesus.0.clone());
|
||||||
|
map.insert(162, form.commitment.0.clone());
|
||||||
|
map.insert(165, form.teachable.0.clone());
|
||||||
|
map.insert(166, form.extra_info.0.clone());
|
||||||
|
map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MtChurchForm {
|
||||||
|
async fn build_email(&self) -> Markup {
|
||||||
|
html! {
|
||||||
|
(DOCTYPE)
|
||||||
|
meta charset="utf-8";
|
||||||
|
html {
|
||||||
|
head {
|
||||||
|
title { (self.first_name.0) " " (self.last_name.0) " signed up for mission trip!" }
|
||||||
|
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 { "Mission trip 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 { "Student" }
|
||||||
|
td { (self.student_first_name.0) " " (self.student_last_name.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Relationship with student" }
|
||||||
|
td { (self.relationship.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Positive characteristics" }
|
||||||
|
td { (self.positive.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Negative characteristics" }
|
||||||
|
td { (self.negative.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Walk with Jesus" }
|
||||||
|
td { (self.walk_jesus.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Commitment" }
|
||||||
|
td { (self.commitment.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Teachable heart" }
|
||||||
|
td { (self.teachable.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Other Relevant Info" }
|
||||||
|
td { (self.extra_info.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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/13/row/757"#;
|
||||||
|
let res = client
|
||||||
|
.post("https://staff.tfcconnection.org/ocs/v2.php/apps/tables/api/2/tables/13/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()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 email = SinglePart::html(email.into_string());
|
||||||
|
|
||||||
|
if let Ok(m) = Message::builder()
|
||||||
|
.from(
|
||||||
|
"TFC ADMIN <no-reply@mail.tfcconnection.org>"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.to("Chris Cochrun <chris@tfcconnection.org>".parse().unwrap())
|
||||||
|
.subject(email_subject)
|
||||||
|
.singlepart(email)
|
||||||
|
{
|
||||||
|
crate::email::send_email(m).await
|
||||||
|
} else {
|
||||||
|
Err(eyre!("Email incorrect"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/api/mt-teacher-form")]
|
||||||
|
pub async fn mt_form(MultipartForm(mut form): MultipartForm<MtChurchForm>) -> HttpResponse {
|
||||||
|
match form.store_form().await {
|
||||||
|
Ok(_) => info!("Successfully sent form to nextcloud!"),
|
||||||
|
Err(e) => error!("There was an erroring sending form to nextcloud: {e}"),
|
||||||
|
}
|
||||||
|
match form.send_email().await {
|
||||||
|
Ok(_) => info!("Successfully sent email"),
|
||||||
|
Err(e) => error!("There was an error sending the email: {e}"),
|
||||||
|
}
|
||||||
|
HttpResponse::Ok().body("thankyou")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use actix_web::test;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use sqlx::Connection;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn form() -> MtChurchForm {
|
||||||
|
MtChurchForm {
|
||||||
|
first_name: Text(String::from("Frodo")),
|
||||||
|
last_name: Text(String::from("Braggins")),
|
||||||
|
student_first_name: Text(String::from("Bilbo")),
|
||||||
|
student_last_name: Text(String::from("Braggins")),
|
||||||
|
relationship: Text(String::from("Uncle")),
|
||||||
|
positive: Text(String::from("Nimble and brave")),
|
||||||
|
negative: Text(String::from("Small")),
|
||||||
|
walk_jesus: Text(String::from("Such a strutter")),
|
||||||
|
commitment: Text(String::from("Super")),
|
||||||
|
teachable: Text(String::from("Very")),
|
||||||
|
extra_info: Text(String::from("Willing to take the ring")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_nc_post() {
|
||||||
|
let form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
let res = form.store_form().await;
|
||||||
|
match res {
|
||||||
|
Ok(_) => assert!(true, "passed storing test"),
|
||||||
|
Err(e) => assert!(false, "Failed storing test: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_email() {
|
||||||
|
let mut form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
match form.send_email().await {
|
||||||
|
Ok(_) => assert!(true, "passed emailing test"),
|
||||||
|
Err(e) => assert!(false, "Failed emailing test: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
233
src/api/mt_parent_form.rs
Normal file
233
src/api/mt_parent_form.rs
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
fs,
|
||||||
|
};
|
||||||
|
|
||||||
|
use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
|
||||||
|
use actix_web::{post, web, HttpResponse};
|
||||||
|
use color_eyre::{eyre::eyre, Result};
|
||||||
|
use lettre::{
|
||||||
|
message::{header::ContentType, Attachment, MultiPart, SinglePart},
|
||||||
|
Message,
|
||||||
|
};
|
||||||
|
use maud::{html, Markup, PreEscaped, DOCTYPE};
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde_json::json;
|
||||||
|
use sqlx::SqliteConnection;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
#[derive(Debug, MultipartForm)]
|
||||||
|
struct MtParentForm {
|
||||||
|
#[multipart(rename = "firstname")]
|
||||||
|
first_name: Text<String>,
|
||||||
|
#[multipart(rename = "lastname")]
|
||||||
|
last_name: Text<String>,
|
||||||
|
#[multipart(rename = "studentfirstname")]
|
||||||
|
student_first_name: Text<String>,
|
||||||
|
#[multipart(rename = "studentlastname")]
|
||||||
|
student_last_name: Text<String>,
|
||||||
|
authority: Text<String>,
|
||||||
|
positive: Text<String>,
|
||||||
|
negative: Text<String>,
|
||||||
|
#[multipart(rename = "family-relation")]
|
||||||
|
family: Text<String>,
|
||||||
|
#[multipart(rename = "previous-trip-info")]
|
||||||
|
previous_trip: Text<String>,
|
||||||
|
#[multipart(rename = "trip-feelings")]
|
||||||
|
feelings: Text<String>,
|
||||||
|
#[multipart(rename = "extra-info")]
|
||||||
|
extra_info: Text<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&MtParentForm> for HashMap<i32, String> {
|
||||||
|
fn from(form: &MtParentForm) -> Self {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(158, format!("{} {}", form.first_name.0, form.last_name.0));
|
||||||
|
map.insert(
|
||||||
|
159,
|
||||||
|
format!("{} {}", form.student_first_name.0, form.student_last_name.0),
|
||||||
|
);
|
||||||
|
map.insert(160, form.authority.0.clone());
|
||||||
|
map.insert(163, form.positive.0.clone());
|
||||||
|
map.insert(164, form.negative.0.clone());
|
||||||
|
map.insert(161, form.family.0.clone());
|
||||||
|
map.insert(162, form.previous_trip.0.clone());
|
||||||
|
map.insert(165, form.feelings.0.clone());
|
||||||
|
map.insert(166, form.extra_info.0.clone());
|
||||||
|
map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MtParentForm {
|
||||||
|
async fn build_email(&self) -> Markup {
|
||||||
|
html! {
|
||||||
|
(DOCTYPE)
|
||||||
|
meta charset="utf-8";
|
||||||
|
html {
|
||||||
|
head {
|
||||||
|
title { (self.first_name.0) " " (self.last_name.0) " signed up for mission trip!" }
|
||||||
|
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 { "Mission trip 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 { "Student" }
|
||||||
|
td { (self.student_first_name.0) " " (self.student_last_name.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Authority" }
|
||||||
|
td { (self.authority.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Positive characteristics" }
|
||||||
|
td { (self.positive.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Negative characteristics" }
|
||||||
|
td { (self.negative.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Family Relations" }
|
||||||
|
td { (self.family.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Previous Trip" }
|
||||||
|
td { (self.previous_trip.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Trip Feelings" }
|
||||||
|
td { (self.feelings.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Other Relevant Info" }
|
||||||
|
td { (self.extra_info.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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/13/row/757"#;
|
||||||
|
let res = client
|
||||||
|
.post("https://staff.tfcconnection.org/ocs/v2.php/apps/tables/api/2/tables/13/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()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 email = SinglePart::html(email.into_string());
|
||||||
|
|
||||||
|
if let Ok(m) = Message::builder()
|
||||||
|
.from(
|
||||||
|
"TFC ADMIN <no-reply@mail.tfcconnection.org>"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.to("Chris Cochrun <chris@tfcconnection.org>".parse().unwrap())
|
||||||
|
.subject(email_subject)
|
||||||
|
.singlepart(email)
|
||||||
|
{
|
||||||
|
crate::email::send_email(m).await
|
||||||
|
} else {
|
||||||
|
Err(eyre!("Email incorrect"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/api/mt-teacher-form")]
|
||||||
|
pub async fn mt_form(MultipartForm(mut form): MultipartForm<MtParentForm>) -> HttpResponse {
|
||||||
|
match form.store_form().await {
|
||||||
|
Ok(_) => info!("Successfully sent form to nextcloud!"),
|
||||||
|
Err(e) => error!("There was an erroring sending form to nextcloud: {e}"),
|
||||||
|
}
|
||||||
|
match form.send_email().await {
|
||||||
|
Ok(_) => info!("Successfully sent email"),
|
||||||
|
Err(e) => error!("There was an error sending the email: {e}"),
|
||||||
|
}
|
||||||
|
HttpResponse::Ok().body("thankyou")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use actix_web::test;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use sqlx::Connection;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn form() -> MtParentForm {
|
||||||
|
MtParentForm {
|
||||||
|
first_name: Text(String::from("Frodo")),
|
||||||
|
last_name: Text(String::from("Braggins")),
|
||||||
|
student_first_name: Text(String::from("Bilbo")),
|
||||||
|
student_last_name: Text(String::from("Braggins")),
|
||||||
|
authority: Text(String::from("Uncle")),
|
||||||
|
positive: Text(String::from("Nimble and brave")),
|
||||||
|
negative: Text(String::from("Small")),
|
||||||
|
family: Text(String::from("Such a strutter")),
|
||||||
|
previous_trip: Text(String::from("Super")),
|
||||||
|
feelings: Text(String::from("Very")),
|
||||||
|
extra_info: Text(String::from("Willing to take the ring")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_nc_post() {
|
||||||
|
let form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
let res = form.store_form().await;
|
||||||
|
match res {
|
||||||
|
Ok(_) => assert!(true, "passed storing test"),
|
||||||
|
Err(e) => assert!(false, "Failed storing test: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_email() {
|
||||||
|
let mut form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
match form.send_email().await {
|
||||||
|
Ok(_) => assert!(true, "passed emailing test"),
|
||||||
|
Err(e) => assert!(false, "Failed emailing test: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
224
src/api/mt_teacher_form.rs
Normal file
224
src/api/mt_teacher_form.rs
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
fs,
|
||||||
|
};
|
||||||
|
|
||||||
|
use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
|
||||||
|
use actix_web::{post, web, HttpResponse};
|
||||||
|
use color_eyre::{eyre::eyre, Result};
|
||||||
|
use lettre::{
|
||||||
|
message::{header::ContentType, Attachment, MultiPart, SinglePart},
|
||||||
|
Message,
|
||||||
|
};
|
||||||
|
use maud::{html, Markup, PreEscaped, DOCTYPE};
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde_json::json;
|
||||||
|
use sqlx::SqliteConnection;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
#[derive(Debug, MultipartForm)]
|
||||||
|
struct MtTeacherForm {
|
||||||
|
#[multipart(rename = "firstname")]
|
||||||
|
first_name: Text<String>,
|
||||||
|
#[multipart(rename = "lastname")]
|
||||||
|
last_name: Text<String>,
|
||||||
|
#[multipart(rename = "studentfirstname")]
|
||||||
|
student_first_name: Text<String>,
|
||||||
|
#[multipart(rename = "studentlastname")]
|
||||||
|
student_last_name: Text<String>,
|
||||||
|
relationship: Text<String>,
|
||||||
|
positive: Text<String>,
|
||||||
|
negative: Text<String>,
|
||||||
|
attitudes: Text<String>,
|
||||||
|
#[multipart(rename = "team-challenges")]
|
||||||
|
challenges: Text<String>,
|
||||||
|
#[multipart(rename = "extra-info")]
|
||||||
|
extra_info: Text<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&MtTeacherForm> for HashMap<i32, String> {
|
||||||
|
fn from(form: &MtTeacherForm) -> Self {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(150, format!("{} {}", form.first_name.0, form.last_name.0));
|
||||||
|
map.insert(
|
||||||
|
151,
|
||||||
|
format!("{} {}", form.student_first_name.0, form.student_last_name.0),
|
||||||
|
);
|
||||||
|
map.insert(152, form.relationship.0.clone());
|
||||||
|
map.insert(153, form.positive.0.clone());
|
||||||
|
map.insert(154, form.negative.0.clone());
|
||||||
|
map.insert(155, form.attitudes.0.clone());
|
||||||
|
map.insert(156, form.challenges.0.clone());
|
||||||
|
map.insert(157, form.extra_info.0.clone());
|
||||||
|
map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MtTeacherForm {
|
||||||
|
async fn build_email(&self) -> Markup {
|
||||||
|
html! {
|
||||||
|
(DOCTYPE)
|
||||||
|
meta charset="utf-8";
|
||||||
|
html {
|
||||||
|
head {
|
||||||
|
title { (self.first_name.0) " " (self.last_name.0) " signed up for mission trip!" }
|
||||||
|
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 { "Mission trip 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 { "Student" }
|
||||||
|
td { (self.student_first_name.0) " " (self.student_last_name.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Relationship with student" }
|
||||||
|
td { (self.relationship.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Positive characteristics" }
|
||||||
|
td { (self.positive.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Negative characteristics" }
|
||||||
|
td { (self.negative.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Attitudes" }
|
||||||
|
td { (self.attitudes.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Teamwork" }
|
||||||
|
td { (self.challenges.0) }
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { "Other Relevant Info" }
|
||||||
|
td { (self.extra_info.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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/12/row/757"#;
|
||||||
|
let res = client
|
||||||
|
.post("https://staff.tfcconnection.org/ocs/v2.php/apps/tables/api/2/tables/12/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()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 email = SinglePart::html(email.into_string());
|
||||||
|
|
||||||
|
if let Ok(m) = Message::builder()
|
||||||
|
.from(
|
||||||
|
"TFC ADMIN <no-reply@mail.tfcconnection.org>"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.to("Chris Cochrun <chris@tfcconnection.org>".parse().unwrap())
|
||||||
|
.subject(email_subject)
|
||||||
|
.singlepart(email)
|
||||||
|
{
|
||||||
|
crate::email::send_email(m).await
|
||||||
|
} else {
|
||||||
|
Err(eyre!("Email incorrect"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/api/mt-teacher-form")]
|
||||||
|
pub async fn mt_form(MultipartForm(mut form): MultipartForm<MtTeacherForm>) -> HttpResponse {
|
||||||
|
match form.store_form().await {
|
||||||
|
Ok(_) => info!("Successfully sent form to nextcloud!"),
|
||||||
|
Err(e) => error!("There was an erroring sending form to nextcloud: {e}"),
|
||||||
|
}
|
||||||
|
match form.send_email().await {
|
||||||
|
Ok(_) => info!("Successfully sent email"),
|
||||||
|
Err(e) => error!("There was an error sending the email: {e}"),
|
||||||
|
}
|
||||||
|
HttpResponse::Ok().body("thankyou")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use actix_web::test;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use sqlx::Connection;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn form() -> MtTeacherForm {
|
||||||
|
MtTeacherForm {
|
||||||
|
first_name: Text(String::from("Frodo")),
|
||||||
|
last_name: Text(String::from("Braggins")),
|
||||||
|
student_first_name: Text(String::from("Bilbo")),
|
||||||
|
student_last_name: Text(String::from("Braggins")),
|
||||||
|
relationship: Text(String::from("Uncle")),
|
||||||
|
positive: Text(String::from("Nimble and brave")),
|
||||||
|
negative: Text(String::from("Small")),
|
||||||
|
attitudes: Text(String::from("Lighthearted")),
|
||||||
|
challenges: Text(String::from("Willing")),
|
||||||
|
extra_info: Text(String::from("Willing to take the ring")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_nc_post() {
|
||||||
|
let form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
let res = form.store_form().await;
|
||||||
|
match res {
|
||||||
|
Ok(_) => assert!(true, "passed storing test"),
|
||||||
|
Err(e) => assert!(false, "Failed storing test: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_email() {
|
||||||
|
let mut form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
match form.send_email().await {
|
||||||
|
Ok(_) => assert!(true, "passed emailing test"),
|
||||||
|
Err(e) => assert!(false, "Failed emailing test: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ async fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
info!("starting HTTP server at http://localhost:4242");
|
info!("starting HTTP server at http://localhost:4242");
|
||||||
|
|
||||||
let conn = SqliteConnection::connect("file://./data.db")
|
let conn = SqliteConnection::connect("sqlite://./data.db")
|
||||||
.await
|
.await
|
||||||
.expect("Couldn't connect sqlite db");
|
.expect("Couldn't connect sqlite db");
|
||||||
let data = web::Data::new(conn);
|
let data = web::Data::new(conn);
|
||||||
|
|
Loading…
Reference in a new issue