Files
zero2prod/src/routes/subscriptions_confirm.rs
Alphonse Paix 1117d49746
Some checks failed
Rust / Test (push) Has been cancelled
Rust / Rustfmt (push) Has been cancelled
Rust / Clippy (push) Has been cancelled
Rust / Code coverage (push) Has been cancelled
Update telemetry
2025-09-28 03:37:23 +02:00

69 lines
2.0 KiB
Rust

use crate::{
routes::{AppError, Query, generate_token, not_found_html},
startup::AppState,
templates::{ConfirmTemplate, HtmlTemplate},
};
use anyhow::Context;
use axum::{
extract::State,
response::{IntoResponse, Response},
};
use serde::Deserialize;
use sqlx::PgPool;
use uuid::Uuid;
#[tracing::instrument(name = "Confirming new subscriber", skip_all)]
pub async fn confirm(
State(AppState {
connection_pool, ..
}): State<AppState>,
Query(params): Query<Params>,
) -> Result<Response, AppError> {
let subscriber_id = get_subscriber_id_from_token(&connection_pool, &params.subscription_token)
.await
.context("Could not fetch subscriber id given subscription token.")?;
if let Some(id) = subscriber_id {
confirm_subscriber(&connection_pool, &id)
.await
.context("Failed to update subscriber status.")?;
let template = HtmlTemplate(ConfirmTemplate);
Ok(template.into_response())
} else {
Ok(not_found_html())
}
}
#[tracing::instrument(name = "Mark subscriber as confirmed", skip(connection_pool))]
async fn confirm_subscriber(
connection_pool: &PgPool,
subscriber_id: &Uuid,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"UPDATE subscriptions SET status = 'confirmed', unsubscribe_token = $1 WHERE id = $2",
generate_token(),
subscriber_id
)
.execute(connection_pool)
.await?;
Ok(())
}
#[tracing::instrument(name = "Get subscriber id from token", skip(connection))]
async fn get_subscriber_id_from_token(
connection: &PgPool,
subscription_token: &str,
) -> Result<Option<Uuid>, sqlx::Error> {
let saved = sqlx::query!(
"SELECT subscriber_id FROM subscription_tokens WHERE subscription_token = $1",
subscription_token
)
.fetch_optional(connection)
.await?;
Ok(saved.map(|r| r.subscriber_id))
}
#[derive(Debug, Deserialize)]
pub struct Params {
subscription_token: String,
}