use crate::{startup::AppState, templates::ConfirmTemplate}; use askama::Template; use axum::{ extract::{Query, State}, http::StatusCode, response::{Html, IntoResponse, Response}, }; use serde::Deserialize; use sqlx::PgPool; use uuid::Uuid; #[tracing::instrument(name = "Confirming new subscriber", skip(params))] pub async fn confirm( State(AppState { connection_pool, .. }): State, Query(params): Query, ) -> Response { let Ok(subscriber_id) = get_subscriber_id_from_token(&connection_pool, ¶ms.subscription_token).await else { return StatusCode::INTERNAL_SERVER_ERROR.into_response(); }; if let Some(subscriber_id) = subscriber_id { if confirm_subscriber(&connection_pool, &subscriber_id) .await .is_err() { StatusCode::INTERNAL_SERVER_ERROR.into_response() } else { Html(ConfirmTemplate.render().unwrap()).into_response() } } else { StatusCode::UNAUTHORIZED.into_response() } } #[tracing::instrument( name = "Mark subscriber as confirmed", skip(connection_pool, subscriber_id) )] async fn confirm_subscriber( connection_pool: &PgPool, subscriber_id: &Uuid, ) -> Result<(), sqlx::Error> { sqlx::query!( "UPDATE subscriptions SET status = 'confirmed' WHERE id = $1", subscriber_id ) .execute(connection_pool) .await .map_err(|e| { tracing::error!("Failed to execute query: {:?}", e); e })?; Ok(()) } #[tracing::instrument( name = "Get subscriber_id from token", skip(connection, subscription_token) )] async fn get_subscriber_id_from_token( connection: &PgPool, subscription_token: &str, ) -> Result, sqlx::Error> { let saved = sqlx::query!( "SELECT subscriber_id FROM subscription_tokens WHERE subscription_token = $1", subscription_token ) .fetch_optional(connection) .await .map_err(|e| { tracing::error!("Failed to execute query: {:?}", e); e })?; Ok(saved.map(|r| r.subscriber_id)) } #[derive(Debug, Deserialize)] pub struct Params { subscription_token: String, }