diff --git a/Cargo.toml b/Cargo.toml index 0121612..b0bd14e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,6 @@ time = { version = "0.3.36", optional = true } fontdb = { version = "0.17.0", optional = true } typst-assets = { version = "0.11.1", features = ["fonts"], optional = true } tempdir = { version = "0.3.7", optional = true } -tokio-rayon = "2.1.0" reqwest = { version = "0.12.5", features = ["multipart"] } [dev-dependencies] diff --git a/src/api/invoices.rs b/src/api/invoices.rs index 33d3a91..ea6de2e 100644 --- a/src/api/invoices.rs +++ b/src/api/invoices.rs @@ -1,4 +1,4 @@ -use crate::database::DatabaseConnection; +use crate::database::{DatabaseConnection, MailgunClient}; use crate::error::Error; use crate::models::{Address, Attachment, Invoice, InvoiceRow}; use axum::{async_trait, body::Bytes, http::StatusCode, Json}; @@ -197,21 +197,15 @@ pub async fn list_all(mut conn: DatabaseConnection) -> Result Result<(), Error> { - let client = reqwest::Client::new(); +pub async fn send_mail( + mailgun_client: MailgunClient, + invoice: &PopulatedInvoice, +) -> Result<(), Error> { + let invoice_recipient = format!("{} <{}>", invoice.recipient_name, invoice.recipient_email); let form = reqwest::multipart::Form::new() - .text( - "from", - std::env::var("MAILGUN_FROM").unwrap_or(String::from("")), - ) - .text( - "to", - format!("{} <{}>", invoice.recipient_name, invoice.recipient_email), - ) - .text( - "to", - std::env::var("MAILGUN_TO").unwrap_or(String::from("")), - ) + .text("from", mailgun_client.from) + .text("to", mailgun_client.default_to) + .text("cc", invoice_recipient) .text("subject", format!("Uusi lasku #{}", invoice.id)) .text("html", format!("Uusi lasku #{}", invoice.id)); @@ -228,12 +222,10 @@ pub async fn send_mail(invoice: &PopulatedInvoice) -> Result<(), Error> { )) })?; - let response = client - .post(std::env::var("MAILGUN_URL").unwrap_or(String::from(""))) - .basic_auth( - std::env::var("MAILGUN_USER").unwrap_or(String::from("")), - Some(std::env::var("MAILGUN_PASSWORD").unwrap_or(String::from(""))), - ) + let response = mailgun_client + .client + .post(mailgun_client.url) + .basic_auth(mailgun_client.api_user, Some(mailgun_client.api_key)) .multipart(form) .send() .await?; diff --git a/src/database/mod.rs b/src/database/mod.rs index b85bc10..bd764ca 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -12,6 +12,7 @@ mod invoices; #[derive(FromRef, Clone)] pub struct State { pool: bb8::Pool>, + mailgun_client: MailgunClient, for_garde: (), } @@ -21,6 +22,15 @@ pub async fn new() -> State { let db_url = std::env::var("DATABASE_URL").expect("No DATABASE_URL in env"); let config = AsyncDieselConnectionManager::::new(db_url); + let mailgun_client = MailgunClient { + client: reqwest::Client::new(), + url: std::env::var("MAILGUN_URL").expect("No MAILGUN_URL in env"), + api_user: std::env::var("MAILGUN_USER").expect("No MAILGUN_USER in env"), + api_key: std::env::var("MAILGUN_PASSWORD").expect("No MAILGUN_PASSWORD in env"), + default_to: std::env::var("MAILGUN_TO").unwrap_or(String::from("")), + from: std::env::var("MAILGUN_FROM").unwrap_or(String::from("")), + }; + State { pool: if cfg!(test) { let pool = bb8::Pool::builder() @@ -40,6 +50,7 @@ pub async fn new() -> State { .await .expect("Failed to build database pool") }, + mailgun_client, for_garde: (), } } @@ -48,6 +59,30 @@ pub struct DatabaseConnection( pub bb8::PooledConnection<'static, AsyncDieselConnectionManager>, ); +#[derive(Clone)] +pub struct MailgunClient { + pub client: reqwest::Client, + pub url: String, + pub api_user: String, + pub api_key: String, + pub default_to: String, + pub from: String, +} + +#[async_trait] +impl FromRequestParts for MailgunClient +where + S: Send + Sync, + State: FromRef, +{ + type Rejection = crate::error::Error; + + async fn from_request_parts(_parts: &mut Parts, state: &S) -> Result { + let state = State::from_ref(state); + Ok(state.mailgun_client) + } +} + #[async_trait] impl FromRequestParts for DatabaseConnection where