77 lines
1.9 KiB
Rust
77 lines
1.9 KiB
Rust
use crate::domain::{NewSubscriber, SubscriberEmail, SubscriberName};
|
|
use axum::{Form, extract::State, http::StatusCode, response::IntoResponse};
|
|
use chrono::Utc;
|
|
use serde::Deserialize;
|
|
use sqlx::PgPool;
|
|
use uuid::Uuid;
|
|
|
|
#[tracing::instrument(
|
|
name = "Adding a new subscriber",
|
|
skip(connection, form),
|
|
fields(
|
|
subscriber_email = %form.email,
|
|
subscriber_name = %form.name
|
|
)
|
|
)]
|
|
pub async fn subscribe(
|
|
State(connection): State<PgPool>,
|
|
Form(form): Form<FormData>,
|
|
) -> impl IntoResponse {
|
|
let new_subscriber = match form.try_into() {
|
|
Ok(subscriber) => subscriber,
|
|
Err(_) => return StatusCode::BAD_REQUEST,
|
|
};
|
|
if insert_subscriber(&connection, &new_subscriber)
|
|
.await
|
|
.is_err()
|
|
{
|
|
StatusCode::INTERNAL_SERVER_ERROR
|
|
} else {
|
|
StatusCode::OK
|
|
}
|
|
}
|
|
|
|
#[tracing::instrument(
|
|
name = "Saving new subscriber details in the database",
|
|
skip(connection, new_subscriber)
|
|
)]
|
|
pub async fn insert_subscriber(
|
|
connection: &PgPool,
|
|
new_subscriber: &NewSubscriber,
|
|
) -> Result<(), sqlx::Error> {
|
|
sqlx::query!(
|
|
r#"
|
|
INSERT INTO subscriptions (id, email, name, subscribed_at)
|
|
VALUES ($1, $2, $3, $4);
|
|
"#,
|
|
Uuid::new_v4(),
|
|
new_subscriber.email.as_ref(),
|
|
new_subscriber.name.as_ref(),
|
|
Utc::now()
|
|
)
|
|
.execute(connection)
|
|
.await
|
|
.map_err(|e| {
|
|
tracing::error!("Failed to execute query: {:?}", e);
|
|
e
|
|
})?;
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
#[allow(dead_code)]
|
|
pub struct FormData {
|
|
name: String,
|
|
email: String,
|
|
}
|
|
|
|
impl TryFrom<FormData> for NewSubscriber {
|
|
type Error = String;
|
|
|
|
fn try_from(value: FormData) -> Result<Self, Self::Error> {
|
|
let name = SubscriberName::parse(value.name)?;
|
|
let email = SubscriberEmail::parse(value.email)?;
|
|
Ok(Self { name, email })
|
|
}
|
|
}
|