Skip to content

Commit

Permalink
after chapter 09
Browse files Browse the repository at this point in the history
  • Loading branch information
SergeFan committed Jan 16, 2025
1 parent e809fea commit 38139c6
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 8 deletions.
10 changes: 5 additions & 5 deletions src/email_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl EmailClient {

pub async fn send_email(
&self,
recipient: SubscriberEmail,
recipient: &SubscriberEmail,
subject: &str,
html_content: &str,
text_content: &str,
Expand Down Expand Up @@ -140,7 +140,7 @@ mod tests {

// Act
let _ = email_client
.send_email(email(), &subject(), &content(), &content())
.send_email(&email(), &subject(), &content(), &content())
.await;

// Assert
Expand All @@ -161,7 +161,7 @@ mod tests {

// Act
let result = email_client
.send_email(email(), &subject(), &content(), &content())
.send_email(&email(), &subject(), &content(), &content())
.await;

// Assert
Expand All @@ -182,7 +182,7 @@ mod tests {

// Act
let result = email_client
.send_email(email(), &subject(), &content(), &content())
.send_email(&email(), &subject(), &content(), &content())
.await;

// Assert
Expand All @@ -203,7 +203,7 @@ mod tests {

// Act
let result = email_client
.send_email(email(), &subject(), &content(), &content())
.send_email(&email(), &subject(), &content(), &content())
.await;

// Assert
Expand Down
69 changes: 67 additions & 2 deletions src/routes/newsletters.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
use std::sync::Arc;

use anyhow::Context;
use axum::extract::rejection::JsonRejection;
use axum::extract::{FromRequest, Json};
use axum::extract::{FromRequest, Json, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use entity::prelude::Subscriptions;
use entity::subscriptions;
use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, SelectColumns};
use serde::Deserialize;

use crate::domain::SubscriberEmail;
use crate::routes::error_chain_fmt;
use crate::startup::ApplicationState;

#[derive(thiserror::Error)]
pub enum PublishError {
#[error(transparent)]
JsonRejection(#[from] JsonRejection),
#[error(transparent)]
UnexpectedError(#[from] anyhow::Error),
}

impl std::fmt::Debug for PublishError {
Expand All @@ -24,6 +34,7 @@ impl IntoResponse for PublishError {

match self {
PublishError::JsonRejection(_) => StatusCode::BAD_REQUEST.into_response(),
PublishError::UnexpectedError(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
}
}
Expand All @@ -45,7 +56,61 @@ pub struct Content {
}

pub async fn publish_newsletters(
PublishBody(_body): PublishBody<BodyData>,
State(state): State<Arc<ApplicationState>>,
PublishBody(body): PublishBody<BodyData>,
) -> Result<Response, PublishError> {
let subscribers = get_confirmed_subscribers(&state.db_connection)
.await
.context("Failed to get confirmed subscribers")?;

for subscriber in subscribers {
match subscriber {
Ok(subscriber) => {
state
.email_client
.send_email(
&subscriber.email,
&body.title,
&body.content.html,
&body.content.text,
)
.await
// `with_context` is lazy so it only allocate memory when email delivery fails
.with_context(|| {
format!("Failed to send newsletter issue to {}", subscriber.email)
})?;
}
Err(error) => {
tracing::warn!(
error.cause_chain = ?error,
"Skipping a confirmed subscriber. The stored contact details are invalid"
)
}
}
}

Ok(StatusCode::OK.into_response())
}

struct ConfirmedSubscriber {
email: SubscriberEmail,
}

#[tracing::instrument(name = "Get confirmed subscribers", skip(db_connection))]
async fn get_confirmed_subscribers(
db_connection: &DatabaseConnection,
) -> Result<Vec<Result<ConfirmedSubscriber, anyhow::Error>>, anyhow::Error> {
let confirmed_subscribers = Subscriptions::find()
.select_column(subscriptions::Column::Email)
.filter(subscriptions::Column::Status.eq("confirmed"))
.all(db_connection)
.await?
.into_iter()
.map(|row| match SubscriberEmail::parse(row.email) {
Ok(email) => Ok(ConfirmedSubscriber { email }),
Err(error) => Err(anyhow::anyhow!(error)),
})
.collect();

Ok(confirmed_subscribers)
}
2 changes: 1 addition & 1 deletion src/routes/subscriptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ pub async fn send_confirmation_email(

email_client
.send_email(
new_subscriber.email,
&new_subscriber.email,
"Welcome!",
&html_body,
&plain_text_body,
Expand Down

0 comments on commit 38139c6

Please sign in to comment.