use std::collections::HashSet;
use axum::{
extract::{Path, Query},
response::{IntoResponse, Redirect},
routing::{get, post},
Extension, Form,
};
use http::HeaderMap;
use uuid::Uuid;
use crate::{auth::ConfirmationKey, email::list::Subscriber, ErrorKind};
use crate::{Result, Router};
use super::{ConfigExt, DbExt};
pub fn router() -> Router {
Router::new()
.route("/mailing/subscribe", post(subscribe))
.route("/mailing/unsubscribe/:subscriber", get(unsubscribe))
.route("/mailing/confirm/:key", get(confirm))
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SubscribeForm {
pub email: String,
pub lists: Option<HashSet<String>>,
}
pub async fn subscribe(
Extension(db): DbExt,
Extension(config): ConfigExt,
Form(form): Form<SubscribeForm>,
) -> Result<impl IntoResponse> {
let mut subscriber = Subscriber::new(form.email);
subscriber.marketing_consent = true;
subscriber.lists = form.lists.unwrap_or(config.mailing.lists.clone());
db.set(&subscriber)?;
if config.mailing.confirmation {
crate::email::mailing_confirmation(subscriber.address, subscriber.id.to_string(), &config)?;
}
Ok("Sent!")
}
pub async fn confirm(
Extension(db): DbExt,
headers: HeaderMap,
Path(key): Path<Uuid>,
) -> Result<impl IntoResponse> {
let mut subscriber = db
.get::<Subscriber>(key)
.map_err(|e| ErrorKind::Other("mailing subscriber verification failed".to_string()))?;
subscriber.confirmed = true;
db.set(&subscriber)?;
Ok(Redirect::to("/?msg=2"))
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct UnsubscribeQuery {
pub lists: Option<HashSet<String>>,
}
pub async fn unsubscribe(
Extension(db): DbExt,
Path(subscriber): Path<Uuid>,
Query(query): Query<UnsubscribeQuery>,
) -> Result<impl IntoResponse> {
let mut sub: Subscriber = db.get(subscriber)?;
if let Some(lists) = query.lists {
sub.lists.retain(|list| !lists.contains(list));
db.set(&sub)?;
}
else {
db.remove(&sub)?;
}
Ok("Success!")
}