mission trip form now posts to nextcloud, skeleton of sqlx
This commit is contained in:
parent
f78e9ea162
commit
87c0d9cb01
819
Cargo.lock
generated
819
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -30,3 +30,5 @@ tracing-appender = "0.2.3"
|
||||||
actix-files = "0.6.6"
|
actix-files = "0.6.6"
|
||||||
tracing-actix-web = "0.7.14"
|
tracing-actix-web = "0.7.14"
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
|
pretty_assertions = "1.4.1"
|
||||||
|
sqlx = { version = "0.8.2", features = ["sqlite"] }
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
use std::fs;
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
fs,
|
||||||
|
};
|
||||||
|
|
||||||
use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
|
use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
|
||||||
use actix_web::{post, HttpResponse};
|
use actix_web::{post, web, HttpResponse};
|
||||||
|
use color_eyre::{eyre::eyre, Result};
|
||||||
use lettre::{
|
use lettre::{
|
||||||
message::{header::ContentType, Attachment, MultiPart, SinglePart},
|
message::{header::ContentType, Attachment, MultiPart, SinglePart},
|
||||||
Message,
|
Message,
|
||||||
};
|
};
|
||||||
use maud::{html, PreEscaped, DOCTYPE};
|
use maud::{html, PreEscaped, DOCTYPE};
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde_json::json;
|
||||||
|
use sqlx::SqliteConnection;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
#[derive(Debug, MultipartForm)]
|
#[derive(Debug, MultipartForm)]
|
||||||
|
@ -63,7 +70,51 @@ struct MtForm {
|
||||||
final_agreement: Text<String>,
|
final_agreement: Text<String>,
|
||||||
registration: Text<String>,
|
registration: Text<String>,
|
||||||
#[multipart(rename = "image")]
|
#[multipart(rename = "image")]
|
||||||
file: TempFile,
|
file: Option<TempFile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&MtForm> for HashMap<i32, String> {
|
||||||
|
fn from(form: &MtForm) -> Self {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(106, format!("{} {}", form.first_name.0, form.last_name.0));
|
||||||
|
map.insert(
|
||||||
|
107,
|
||||||
|
format!("{} {}", form.parent_first_name.0, form.parent_last_name.0),
|
||||||
|
);
|
||||||
|
map.insert(109, form.gender.0.clone());
|
||||||
|
map.insert(110, form.birthdate.0.clone());
|
||||||
|
map.insert(117, form.street.0.clone());
|
||||||
|
map.insert(118, form.city.0.clone());
|
||||||
|
map.insert(119, form.zip.0.to_string());
|
||||||
|
map.insert(120, form.state.0.clone());
|
||||||
|
map.insert(121, form.cellphone.0.clone());
|
||||||
|
map.insert(122, form.email.0.clone());
|
||||||
|
map.insert(123, form.parentphone.0.clone());
|
||||||
|
map.insert(124, form.parentemail.0.clone());
|
||||||
|
map.insert(125, form.school.0.clone());
|
||||||
|
map.insert(126, form.grade.0.clone());
|
||||||
|
map.insert(
|
||||||
|
127,
|
||||||
|
format!("{} {}", form.pastor_first_name.0, form.pastor_last_name.0),
|
||||||
|
);
|
||||||
|
map.insert(128, form.church_attendance.0.clone());
|
||||||
|
map.insert(129, form.tfc_group.0.clone());
|
||||||
|
map.insert(130, form.shirt.0.clone());
|
||||||
|
map.insert(131, form.trip.0.clone());
|
||||||
|
map.insert(132, form.trip_notes.0.clone());
|
||||||
|
map.insert(133, form.relationship_with_jesus.0.clone());
|
||||||
|
map.insert(134, form.testimony.0.clone());
|
||||||
|
map.insert(135, form.involvement_with_group.0.clone());
|
||||||
|
map.insert(136, form.reasons.0.clone());
|
||||||
|
map.insert(137, form.strengths.0.clone());
|
||||||
|
map.insert(138, form.weaknesses.0.clone());
|
||||||
|
map.insert(139, form.previous_trip_info.0.clone());
|
||||||
|
map.insert(140, form.attitude.0.clone());
|
||||||
|
map.insert(141, form.relevant_notes.0.clone());
|
||||||
|
map.insert(144, form.final_agreement.0.clone());
|
||||||
|
map.insert(145, form.registration.0.clone());
|
||||||
|
map
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MtForm {
|
impl MtForm {
|
||||||
|
@ -216,6 +267,33 @@ impl MtForm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn store_form(&self) -> Result<()> {
|
||||||
|
let client = Client::new();
|
||||||
|
let map = HashMap::from(self);
|
||||||
|
let mut json = HashMap::new();
|
||||||
|
dbg!(&map);
|
||||||
|
json.insert("data", map);
|
||||||
|
let res = client
|
||||||
|
.post("https://staff.tfcconnection.org/ocs/v2.php/apps/tables/api/2/tables/9/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?;
|
||||||
|
dbg!(&res);
|
||||||
|
if res.status().is_success() {
|
||||||
|
let res = res.text().await.unwrap();
|
||||||
|
dbg!(res);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(eyre!(
|
||||||
|
"Problem in storing data: {:?}",
|
||||||
|
res.error_for_status()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/api/mt-form")]
|
#[post("/api/mt-form")]
|
||||||
|
@ -229,15 +307,22 @@ pub async fn mt_form(MultipartForm(form): MultipartForm<MtForm>) -> HttpResponse
|
||||||
let mut path = String::from("");
|
let mut path = String::from("");
|
||||||
let mut file_exists = false;
|
let mut file_exists = false;
|
||||||
let mut filename = String::from("");
|
let mut filename = String::from("");
|
||||||
if let Some(file) = form.file.file_name {
|
|
||||||
if let Some(ext) = file.rsplit('.').next() {
|
match form.store_form().await {
|
||||||
|
Ok(_) => info!("Successfully sent form to nextcloud!"),
|
||||||
|
Err(e) => error!("There was an erroring sending form to nextcloud: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(file) = form.file {
|
||||||
|
if let Some(file_str) = file.file_name {
|
||||||
|
if let Some(ext) = file_str.rsplit('.').next() {
|
||||||
filename = format!("{}.{}", filename_noext, ext);
|
filename = format!("{}.{}", filename_noext, ext);
|
||||||
path = format!("./tmp/{}.{}", filename_noext, ext);
|
path = format!("./tmp/{}.{}", filename_noext, ext);
|
||||||
} else {
|
} else {
|
||||||
path = format!("./tmp/{}", file);
|
path = format!("./tmp/{}", file_str);
|
||||||
}
|
}
|
||||||
info!("saving to {}", path);
|
info!("saving to {}", path);
|
||||||
match form.file.file.persist(&path) {
|
match file.file.persist(&path) {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
if f.metadata().unwrap().len() > 0 {
|
if f.metadata().unwrap().len() > 0 {
|
||||||
file_exists = true;
|
file_exists = true;
|
||||||
|
@ -247,6 +332,7 @@ pub async fn mt_form(MultipartForm(form): MultipartForm<MtForm>) -> HttpResponse
|
||||||
Err(e) => info!("{:?}: Probably a missing image", e),
|
Err(e) => info!("{:?}: Probably a missing image", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let multi = if file_exists {
|
let multi = if file_exists {
|
||||||
let filebody = fs::read(path);
|
let filebody = fs::read(path);
|
||||||
|
@ -278,3 +364,68 @@ pub async fn mt_form(MultipartForm(form): MultipartForm<MtForm>) -> HttpResponse
|
||||||
|
|
||||||
HttpResponse::Ok().body("thankyou")
|
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() -> MtForm {
|
||||||
|
MtForm {
|
||||||
|
first_name: Text(String::from("Frodo")),
|
||||||
|
last_name: Text(String::from("Braggins")),
|
||||||
|
parent_first_name: Text(String::from("Bilbo")),
|
||||||
|
parent_last_name: Text(String::from("Braggins")),
|
||||||
|
birthdate: Text(String::from("1845-09-12")),
|
||||||
|
gender: Text(String::from("male")),
|
||||||
|
street: Text(String::from("1234 Bag End")),
|
||||||
|
city: Text(String::from("The Shire")),
|
||||||
|
state: Text(String::from("Hobbiton")),
|
||||||
|
zip: Text(88888),
|
||||||
|
cellphone: Text(String::from("7868889797")),
|
||||||
|
parentphone: Text(String::from("1234567898")),
|
||||||
|
email: Text(String::from("frodo@hobbits.com")),
|
||||||
|
parentemail: Text(String::from("bilbo@hobbits.com")),
|
||||||
|
school: Text(String::from("Shire High")),
|
||||||
|
grade: Text(String::from("junior")),
|
||||||
|
pastor_first_name: Text(String::from("Gandalf")),
|
||||||
|
pastor_last_name: Text(String::from("The White")),
|
||||||
|
church_attendance: Text(String::from("often")),
|
||||||
|
tfc_group: Text(String::from("Northern Valley")),
|
||||||
|
shirt: Text(String::from("medium")),
|
||||||
|
trip: Text(String::from("Mordor")),
|
||||||
|
trip_notes: Text(String::from("If it must happen, I'll do it.")),
|
||||||
|
relationship_with_jesus: Text(String::from("Cool beans")),
|
||||||
|
testimony: Text(String::from("Nephew of Bilbo Braggins")),
|
||||||
|
involvement_with_group: Text(String::from("Good friends with Gandalf")),
|
||||||
|
reasons: Text(String::from("Want an adventure")),
|
||||||
|
strengths: Text(String::from("Willing, brave, small, and curious")),
|
||||||
|
weaknesses: Text(String::from("Not strong, or good with weapons")),
|
||||||
|
previous_trip_info: Text(String::from("The edge of Hob Hill")),
|
||||||
|
attitude: Text(String::from("Willing")),
|
||||||
|
relevant_notes: Text(String::from("Willing to take the ring")),
|
||||||
|
final_agreement: Text(String::from("yes")),
|
||||||
|
registration: Text(String::from("later")),
|
||||||
|
file: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn test_nc_post() {
|
||||||
|
let form = form();
|
||||||
|
assert!(!form.first_name.is_empty());
|
||||||
|
dbg!(&form);
|
||||||
|
// let conn = SqliteConnection::connect("file://./data.db")
|
||||||
|
// .await
|
||||||
|
// .expect("Couldn't connect sqlite db");
|
||||||
|
let res = form.store_form().await;
|
||||||
|
match res {
|
||||||
|
Ok(_) => assert!(true, "passed storing test"),
|
||||||
|
Err(e) => assert!(false, "Failed storing test: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -5,7 +5,7 @@ use actix_files::Files;
|
||||||
use actix_multipart::form::tempfile::TempFileConfig;
|
use actix_multipart::form::tempfile::TempFileConfig;
|
||||||
use actix_web::body::MessageBody;
|
use actix_web::body::MessageBody;
|
||||||
use actix_web::dev::{ServiceRequest, ServiceResponse};
|
use actix_web::dev::{ServiceRequest, ServiceResponse};
|
||||||
use actix_web::{App, Error, HttpServer};
|
use actix_web::{web, App, Error, HttpServer};
|
||||||
use api::camp_form::camp_form;
|
use api::camp_form::camp_form;
|
||||||
use api::church_form::church_form;
|
use api::church_form::church_form;
|
||||||
use api::health_form::health_form;
|
use api::health_form::health_form;
|
||||||
|
@ -15,6 +15,7 @@ use api::parent_form::parent_form;
|
||||||
use api::teacher_form::teacher_form;
|
use api::teacher_form::teacher_form;
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
|
use sqlx::{Connection, SqliteConnection};
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing::{info, Span};
|
use tracing::{info, Span};
|
||||||
use tracing_actix_web::{RootSpanBuilder, TracingLogger};
|
use tracing_actix_web::{RootSpanBuilder, TracingLogger};
|
||||||
|
@ -76,8 +77,14 @@ async fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
info!("starting HTTP server at http://localhost:4242");
|
info!("starting HTTP server at http://localhost:4242");
|
||||||
|
|
||||||
HttpServer::new(|| {
|
let conn = SqliteConnection::connect("file://./data.db")
|
||||||
|
.await
|
||||||
|
.expect("Couldn't connect sqlite db");
|
||||||
|
let data = web::Data::new(conn);
|
||||||
|
|
||||||
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
|
.app_data(data.clone())
|
||||||
.wrap(TracingLogger::<DomainRootSpanBuilder>::new())
|
.wrap(TracingLogger::<DomainRootSpanBuilder>::new())
|
||||||
.app_data(TempFileConfig::default().directory("./tmp"))
|
.app_data(TempFileConfig::default().directory("./tmp"))
|
||||||
.service(mt_form)
|
.service(mt_form)
|
||||||
|
|
Loading…
Reference in a new issue