use chrono::{Local, TimeZone};
use either::Either;
mod forms;
use forms::FormSubmission;
mod mailer;
use mailer::{default_subject_line, send_email, OptionalFields};
mod mail_template;
use rocket::{
form::Form,
http::Status,
response::{status::BadRequest, Redirect},
serde::json::Json,
{get, launch, post, routes},
};
mod spam;
mod strings;
use strings::{SUCCESS_MSG, VERSION, WELCOME_MSG};
mod stripe_orders;
use stripe_orders::find_order_info;
use validator::Validate;
mod webhooks;
use webhooks::{StripeData, StripeEvent};
type FormResponse = Either<(Status, &'static str), Redirect>;
type FormData<'b> = Either<&'b Form<FormSubmission<'b>>, &'b Json<FormSubmission<'b>>>;
fn process_form_data(form_data: FormData) -> Result<(), BadRequest<String>> {
let (
validated,
is_spam,
email,
full_name,
subject,
message,
from_site,
last_name,
company_name,
phone_number,
) = match form_data {
Either::Left(form_data) => (
form_data.validate(),
form_data.check_if_spam(),
form_data.email.trim(),
form_data.full_name,
form_data.subject,
form_data.message,
form_data.from_site,
form_data.last_name,
form_data.company_name,
form_data.phone_number,
),
Either::Right(form_data) => (
form_data.validate(),
form_data.check_if_spam(),
form_data.email.trim(),
form_data.full_name,
form_data.subject,
form_data.message,
form_data.from_site,
form_data.last_name,
form_data.company_name,
form_data.phone_number,
),
};
if let Err(error) = validated {
Err(BadRequest(error.to_string()))
} else {
is_spam?;
let optional_fields = OptionalFields {
last_name,
company_name,
phone_number,
message_summary: None,
cta_link: None,
logo_img: None,
ordered_items: None,
};
send_email(
email,
full_name,
subject,
message,
from_site,
optional_fields,
)
.map_err(|err| BadRequest(err.to_string()))
}
}
fn process_webhook_data(webhook_data: Json<StripeEvent>) -> Result<(), BadRequest<String>> {
let (
order_total,
order_created,
order_currency,
order_id,
order_type,
order_paid,
order_receipt_url,
order_status,
customer_name,
customer_email,
statement_desc,
) = match &webhook_data.data {
StripeData::StripeCharge { object } => (
object.amount,
object.created,
object.currency,
object.id,
webhook_data.event_type,
object.paid,
object.receipt_url,
object.status,
object.billing_details.name,
object.billing_details.email,
object.calculated_statement_descriptor,
),
StripeData::StripeCheckout { object } => (
object.amount_total,
object.created,
object.currency,
object.id,
webhook_data.event_type,
object.payment_status == "paid",
None,
object.status,
object.customer_details.name,
object.customer_details.email,
None,
),
};
if order_paid {
let items = if order_type == "checkout.session.completed" {
find_order_info(order_id)?
} else {
return Ok(());
};
let currency = if order_currency == "usd" { "$" } else { "" };
let order_msg = if let Some(date) = Local.timestamp_opt(order_created, 0).single() {
format!(
"{customer_name} placed an order on {date} for {currency}{}. Order status was {order_status}.",
(order_total as f32 / 100.0)
)
} else {
format!(
"{customer_name} placed an order for {currency}{}. Order status was {order_status}.",
(order_total as f32 / 100.0)
)
};
let optional_fields = OptionalFields {
company_name: None,
last_name: None,
phone_number: None,
message_summary: Some("A new Stripe order has been successfully created!"),
cta_link: order_receipt_url,
ordered_items: Some(&items),
logo_img: if statement_desc.is_some() && statement_desc.unwrap() == "SIMPLY SOURDOUGH" {
None
} else {
None
},
};
send_email(
customer_email,
customer_name,
optional_fields.message_summary.unwrap_or("New message"),
&order_msg,
"Stripe",
optional_fields,
)
.map_err(|err| BadRequest(err.to_string()))
} else {
Err(BadRequest("Payment did not go through".to_string()))
}
}
#[get("/")]
fn index() -> String {
format!("{WELCOME_MSG}\nv{VERSION}")
}
#[post("/", data = "<form>")]
fn submit(form: Form<FormSubmission>) -> Result<FormResponse, BadRequest<String>> {
process_form_data(Either::Left(&form)).map(|_| {
if let Some(redirect) = form.redirect {
if redirect {
return Either::Right(Redirect::to(form.from_site.to_string()));
}
}
Either::Left((Status::Ok, SUCCESS_MSG))
})
}
#[post("/", format = "json", data = "<form>", rank = 2)]
fn submit_json(form: Json<FormSubmission>) -> Result<(Status, &'static str), BadRequest<String>> {
process_form_data(Either::Right(&form)).map(|_| (Status::Ok, SUCCESS_MSG))
}
#[post("/webhook", format = "json", data = "<hooks>")]
fn submit_webhook(hooks: Json<StripeEvent>) -> Result<(Status, &'static str), BadRequest<String>> {
process_webhook_data(hooks).map(|_| (Status::Ok, "Order data processed successfully."))
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index, submit, submit_json, submit_webhook])
}
#[cfg(test)]
mod tests;