use crate::prelude2::*;
use crate::commons::validatorr::validation_flatten;
use crate::core::auth0::UserId;
use crate::idempotency::{IdempotencyKey, NextAction};
use crate::services::idempotency_service::save_response;
use crate::services::idempotency_service::try_processing;
use crate::services::newsletter_service::enqueue_delivery_tasks;
use crate::services::newsletter_service::get_confirmed_subscribers;
use crate::services::newsletter_service::insert_newsletter_issue;
use crate::services::newsletter_service::NewsletterFormData;
use actix_web_flash_messages::IncomingFlashMessages;
fn success_message() {
crate::core::flash_messages::send_flash_message("The newsletter issue has been published!");
}
fn success_message_v2() {
crate::core::flash_messages::send_flash_message(
"The newsletter issue has been accepted - \
emails will go out shortly.",
);
}
pub async fn publish_newsletter_form(
_app_state: web::Data<AppContext>,
_user_id: web::ReqData<UserId>,
flash_messages: IncomingFlashMessages,
request: HttpRequest,
) -> impl Responder {
let idempotency_key = uuid::Uuid::now_v7();
let _flash_html = crate::core::flash_messages::get_flash_message_html(&flash_messages);
let mut ctx = tera::Context::new();
ctx.insert("__flash_message", &_flash_html);
ctx.insert("idempotency_key", &idempotency_key);
request.render(200, "subscription/newsletter.html", ctx)
}
pub async fn publish_newsletter(
form: web::Form<NewsletterFormData>,
app_state: web::Data<AppContext>,
user_id: web::ReqData<UserId>,
request: HttpRequest,
) -> Result<HttpResponse> {
if let Some(err) = validation_flatten(&form.0) {
return request.json(200, R::invalid(err));
}
let NewsletterFormData {
title,
html_content,
idempotency_key,
} = form.0;
let _idempotency_key: IdempotencyKey =
idempotency_key.try_into().map_err(Error::UnexpectedError)?;
let user_id = user_id.into_inner();
let ll = try_processing(app_state.mysql(), &_idempotency_key, user_id.to_string()).await?;
match ll {
NextAction::StartProcessing(_) => {}
NextAction::ReturnSavedResponse(saved_response) => {
success_message();
return Ok(saved_response);
}
}
let _subscribers = get_confirmed_subscribers(app_state.mysql())
.await
.map_err(Error::run_time)?;
for subscriber in _subscribers {
match subscriber {
Ok(subscriber) => {
let _receive_email = subscriber.email;
match app_state
.email_client
.send_email(&_receive_email, &title, &html_content)
.await
{
Ok(_) => (),
Err(e) => {
log::error!(
"Send email failed: receiver={}, title={}, error_message={:?}",
&_receive_email,
&title,
e
);
}
}
}
Err(e) => {
log::error!(
"Skipping a confirmed subscriber. \
Their stored contact emails are invalid, error={}",
e
);
}
}
}
success_message();
let response = crate::utils::see_other("/newsletters");
let response = save_response(
app_state.mysql(),
&_idempotency_key,
user_id.to_string(),
response,
)
.await?;
Ok(response)
}
pub async fn publish_newsletter_v2(
form: web::Form<NewsletterFormData>,
app_state: web::Data<AppContext>,
user_id: web::ReqData<UserId>,
request: HttpRequest,
) -> Result<HttpResponse> {
if let Some(err) = validation_flatten(&form.0) {
return request.json(200, R::invalid(err));
}
let NewsletterFormData {
title,
html_content,
idempotency_key,
} = form.0;
let _idempotency_key: IdempotencyKey =
idempotency_key.try_into().map_err(Error::UnexpectedError)?;
let user_id = user_id.into_inner();
let ll = try_processing(app_state.mysql(), &_idempotency_key, user_id.to_string()).await?;
let mut transaction = match ll {
NextAction::StartProcessing(t) => t,
NextAction::ReturnSavedResponse(saved_response) => {
success_message_v2();
return Ok(saved_response);
}
};
let _issue_id = insert_newsletter_issue(&mut transaction, &title, &html_content)
.await
.context("Failed to store newsletter issue details")
.map_err(Error::UnexpectedError)?;
enqueue_delivery_tasks(&mut transaction, _issue_id)
.await
.context("Failed to enqueue delivery tasks")
.map_err(Error::UnexpectedError)?;
let response = crate::utils::see_other("/newsletters");
let response = save_response(
app_state.mysql(),
&_idempotency_key,
user_id.to_string(),
response,
)
.await?;
transaction
.commit()
.await
.context("Failed to commit SQL transaction for publish_newsletter_v2.")
.map_err(Error::UnexpectedError)?;
success_message_v2();
Ok(response)
}