ztp/src/routes/subscribe.rs

60 lines
1.7 KiB
Rust

use crate::errors::ZTPError;
use crate::session_id::SessionId;
use axum::{http::StatusCode, Extension, Form};
use chrono::{DateTime, Utc};
use sqlx::types::Uuid;
use sqlx::PgPool;
#[derive(serde::Deserialize)]
pub(crate) struct NewSubscription {
pub email: String,
pub name: String,
}
#[derive(serde::Deserialize, serde::Serialize, sqlx::FromRow)]
struct Subscription {
pub id: Uuid,
pub email: String,
pub name: String,
pub subscribed_at: DateTime<Utc>,
}
impl From<&NewSubscription> for Subscription {
fn from(s: &NewSubscription) -> Self {
Subscription {
id: Uuid::new_v4(),
email: s.email.clone(),
name: s.name.clone(),
subscribed_at: Utc::now(),
}
}
}
pub(crate) async fn subscribe(
Extension(session): Extension<SessionId>,
Extension(pool): Extension<PgPool>,
payload: Option<Form<NewSubscription>>,
) -> Result<(StatusCode, ()), ZTPError> {
if let Some(payload) = payload {
let sql = "INSERT INTO subscriptions (id, email, name, subscribed_at) VALUES ($1, $2, $3, $4);".to_string();
let subscription: Subscription = (&(payload.0)).into();
tracing::info!(
"request_id {} - Adding '{}' as a new subscriber.",
session.0.to_string(),
subscription.name
);
sqlx::query(&sql)
.bind(subscription.id)
.bind(subscription.email)
.bind(subscription.name)
.bind(subscription.subscribed_at)
.execute(&pool)
.await
.map_or(Err(ZTPError::DuplicateEmail), |_| Ok((StatusCode::OK, ())))
} else {
Err(ZTPError::FormIncomplete)
}
}