Adding and reorganizing some email helpers.

invite_instances
Dessalines 2021-12-06 16:43:25 -05:00
parent b0385830ed
commit d17470c86c
8 changed files with 170 additions and 127 deletions

View File

@ -10,6 +10,9 @@ use lemmy_api_common::{
is_admin, is_admin,
password_length_check, password_length_check,
person::*, person::*,
send_email_verification_success,
send_password_reset_email,
send_verification_email,
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
diesel_option_overwrite, diesel_option_overwrite,
@ -47,14 +50,12 @@ use lemmy_db_views_actor::{
}; };
use lemmy_utils::{ use lemmy_utils::{
claims::Claims, claims::Claims,
email::send_email,
location_info, location_info,
utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix}, utils::{is_valid_display_name, is_valid_matrix_id, naive_from_unix},
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
use lemmy_websocket::{ use lemmy_websocket::{
email::send_verification_email,
messages::{CaptchaItem, SendAllMessage}, messages::{CaptchaItem, SendAllMessage},
LemmyContext, LemmyContext,
UserOperation, UserOperation,
@ -96,6 +97,10 @@ impl Perform for Login {
return Err(LemmyError::from_message("email_not_verified")); return Err(LemmyError::from_message("email_not_verified"));
} }
if site.require_application && !local_user_view.local_user.accepted_application {
return Err(LemmyError::from_message("registration_application_pending"));
}
// Return the jwt // Return the jwt
Ok(LoginResponse { Ok(LoginResponse {
jwt: Some( jwt: Some(
@ -187,7 +192,8 @@ impl Perform for SaveUserSettings {
local_user_view.local_user.id, local_user_view.local_user.id,
email, email,
&local_user_view.person.name, &local_user_view.person.name,
context, context.pool(),
&context.settings(),
) )
.await?; .await?;
None None
@ -774,31 +780,8 @@ impl Perform for PasswordReset {
.map_err(LemmyError::from) .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?; .map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?;
// Generate a random token
let token = generate_random_string();
// Insert the row
let token2 = token.clone();
let local_user_id = local_user_view.local_user.id;
blocking(context.pool(), move |conn| {
PasswordResetRequest::create_token(conn, local_user_id, &token2)
})
.await??;
// Email the pure token to the user. // Email the pure token to the user.
// TODO no i18n support here. send_password_reset_email(&local_user_view, context.pool(), &context.settings()).await?;
let email = &local_user_view.local_user.email.expect("email");
let subject = &format!("Password reset for {}", local_user_view.person.name);
let protocol_and_hostname = &context.settings().get_protocol_and_hostname();
let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", local_user_view.person.name, protocol_and_hostname, &token);
send_email(
subject,
email,
&local_user_view.person.name,
html,
&context.settings(),
)?;
Ok(PasswordResetResponse {}) Ok(PasswordResetResponse {})
} }
} }
@ -963,6 +946,13 @@ impl Perform for VerifyEmail {
}) })
.await??; .await??;
let local_user_view = blocking(context.pool(), move |conn| {
LocalUserView::read(conn, local_user_id)
})
.await??;
send_email_verification_success(&local_user_view, &context.settings())?;
Ok(VerifyEmailResponse {}) Ok(VerifyEmailResponse {})
} }
} }

View File

@ -9,6 +9,7 @@ use lemmy_api_common::{
get_local_user_view_from_jwt, get_local_user_view_from_jwt,
get_local_user_view_from_jwt_opt, get_local_user_view_from_jwt_opt,
is_admin, is_admin,
send_application_approved_email,
site::*, site::*,
}; };
use lemmy_apub::{ use lemmy_apub::{
@ -656,6 +657,14 @@ impl Perform for ApproveRegistrationApplication {
}) })
.await??; .await??;
let require_email_verification = blocking(context.pool(), Site::read_simple)
.await??
.require_email_verification;
if require_email_verification && data.approve {
send_application_approved_email(&local_user_view, &context.settings())?;
}
// Read the view // Read the view
let registration_application = blocking(context.pool(), move |conn| { let registration_application = blocking(context.pool(), move |conn| {
RegistrationApplicationView::read(conn, app_id) RegistrationApplicationView::read(conn, app_id)

View File

@ -10,6 +10,8 @@ use lemmy_db_schema::{
newtypes::{CommunityId, LocalUserId, PersonId, PostId}, newtypes::{CommunityId, LocalUserId, PersonId, PostId},
source::{ source::{
community::Community, community::Community,
email_verification::{EmailVerification, EmailVerificationForm},
password_reset_request::PasswordResetRequest,
person_block::PersonBlock, person_block::PersonBlock,
post::{Post, PostRead, PostReadForm}, post::{Post, PostRead, PostReadForm},
secret::Secret, secret::Secret,
@ -23,7 +25,14 @@ use lemmy_db_views_actor::{
community_person_ban_view::CommunityPersonBanView, community_person_ban_view::CommunityPersonBanView,
community_view::CommunityView, community_view::CommunityView,
}; };
use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, LemmyError, Sensitive}; use lemmy_utils::{
claims::Claims,
email::send_email,
settings::structs::{FederationConfig, Settings},
utils::generate_random_string,
LemmyError,
Sensitive,
};
use url::Url; use url::Url;
pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError> pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
@ -333,3 +342,122 @@ pub fn honeypot_check(honeypot: &Option<String>) -> Result<(), LemmyError> {
Ok(()) Ok(())
} }
} }
pub fn send_email_to_user(
local_user_view: &LocalUserView,
subject_text: &str,
body_text: &str,
comment_content: &str,
settings: &Settings,
) {
if local_user_view.person.banned || !local_user_view.local_user.send_notifications_to_email {
return;
}
if let Some(user_email) = &local_user_view.local_user.email {
let subject = &format!(
"{} - {} {}",
subject_text, settings.hostname, local_user_view.person.name,
);
let html = &format!(
"<h1>{}</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
body_text,
local_user_view.person.name,
comment_content,
settings.get_protocol_and_hostname()
);
match send_email(
subject,
user_email,
&local_user_view.person.name,
html,
settings,
) {
Ok(_o) => _o,
Err(e) => tracing::error!("{}", e),
};
}
}
pub async fn send_password_reset_email(
local_user_view: &LocalUserView,
pool: &DbPool,
settings: &Settings,
) -> Result<(), LemmyError> {
// Generate a random token
let token = generate_random_string();
// Insert the row
let token2 = token.clone();
let local_user_id = local_user_view.local_user.id;
blocking(pool, move |conn| {
PasswordResetRequest::create_token(conn, local_user_id, &token2)
})
.await??;
let email = &local_user_view.local_user.email.to_owned().expect("email");
let subject = &format!("Password reset for {}", local_user_view.person.name);
let protocol_and_hostname = settings.get_protocol_and_hostname();
let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", local_user_view.person.name, protocol_and_hostname, &token);
send_email(subject, email, &local_user_view.person.name, html, settings)
}
/// Send a verification email
pub async fn send_verification_email(
local_user_id: LocalUserId,
new_email: &str,
username: &str,
pool: &DbPool,
settings: &Settings,
) -> Result<(), LemmyError> {
let form = EmailVerificationForm {
local_user_id,
email: new_email.to_string(),
verification_token: generate_random_string(),
};
let verify_link = format!(
"{}/verify_email/{}",
settings.get_protocol_and_hostname(),
&form.verification_token
);
blocking(pool, move |conn| EmailVerification::create(conn, &form)).await??;
let subject = format!("Verify your email address for {}", settings.hostname);
let body = format!(
concat!(
"Please click the link below to verify your email address ",
"for the account @{}@{}. Ignore this email if the account isn't yours.\n\n",
"<a href=\"{}\"></a>"
),
username, settings.hostname, verify_link
);
send_email(&subject, new_email, username, &body, settings)?;
Ok(())
}
pub fn send_email_verification_success(
local_user_view: &LocalUserView,
settings: &Settings,
) -> Result<(), LemmyError> {
let email = &local_user_view.local_user.email.to_owned().expect("email");
let subject = &format!("Email verified for {}", local_user_view.person.name);
let html = "Your email has been verified.";
send_email(subject, email, &local_user_view.person.name, html, settings)
}
pub fn send_application_approved_email(
local_user_view: &LocalUserView,
settings: &Settings,
) -> Result<(), LemmyError> {
let email = &local_user_view.local_user.email.to_owned().expect("email");
let subject = &format!(
"Registration to {} approved for {}",
settings.hostname, local_user_view.person.name
);
let html = &format!(
"Your registration application has been approved. Welcome to {}!",
settings.hostname
);
send_email(subject, email, &local_user_view.person.name, html, settings)
}

View File

@ -5,6 +5,7 @@ use lemmy_api_common::{
check_person_block, check_person_block,
get_local_user_view_from_jwt, get_local_user_view_from_jwt,
person::{CreatePrivateMessage, PrivateMessageResponse}, person::{CreatePrivateMessage, PrivateMessageResponse},
send_email_to_user,
}; };
use lemmy_apub::{ use lemmy_apub::{
generate_local_apub_endpoint, generate_local_apub_endpoint,
@ -20,11 +21,7 @@ use lemmy_db_schema::{
}; };
use lemmy_db_views::local_user_view::LocalUserView; use lemmy_db_views::local_user_view::LocalUserView;
use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError}; use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError};
use lemmy_websocket::{ use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
send::{send_email_to_user, send_pm_ws_message},
LemmyContext,
UserOperationCrud,
};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for CreatePrivateMessage { impl PerformCrud for CreatePrivateMessage {

View File

@ -1,6 +1,12 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{blocking, honeypot_check, password_length_check, person::*}; use lemmy_api_common::{
blocking,
honeypot_check,
password_length_check,
person::*,
send_verification_email,
};
use lemmy_apub::{ use lemmy_apub::{
generate_followers_url, generate_followers_url,
generate_inbox_url, generate_inbox_url,
@ -34,7 +40,7 @@ use lemmy_utils::{
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
use lemmy_websocket::{email::send_verification_email, messages::CheckCaptcha, LemmyContext}; use lemmy_websocket::{messages::CheckCaptcha, LemmyContext};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for Register { impl PerformCrud for Register {
@ -258,7 +264,8 @@ impl PerformCrud for Register {
// we check at the beginning of this method that email is set // we check at the beginning of this method that email is set
&inserted_local_user.email.expect("email was provided"), &inserted_local_user.email.expect("email was provided"),
&inserted_person.name, &inserted_person.name,
context, context.pool(),
&context.settings(),
) )
.await?; .await?;
LoginResponse { LoginResponse {

View File

@ -1,45 +0,0 @@
use crate::LemmyContext;
use lemmy_api_common::blocking;
use lemmy_db_schema::{
newtypes::LocalUserId,
source::email_verification::{EmailVerification, EmailVerificationForm},
traits::Crud,
};
use lemmy_utils::{email::send_email, utils::generate_random_string, LemmyError};
pub async fn send_verification_email(
local_user_id: LocalUserId,
new_email: &str,
username: &str,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let settings = context.settings();
let form = EmailVerificationForm {
local_user_id,
email: new_email.to_string(),
verification_token: generate_random_string(),
};
// TODO: link should be replaced with a frontend route once that exists
let verify_link = format!(
"{}/api/v3/user/verify_email?token={}",
settings.get_protocol_and_hostname(),
&form.verification_token
);
blocking(context.pool(), move |conn| {
EmailVerification::create(conn, &form)
})
.await??;
let subject = format!("Verify your email address for {}", settings.hostname);
let body = format!(
concat!(
"Please click the link below to verify your email address ",
"for the account @{}@{}. Ignore this email if the account isn't yours.\n\n",
"<a href=\"{}\"></a>"
),
username, settings.hostname, verify_link
);
send_email(&subject, new_email, username, &body, &context.settings())?;
Ok(())
}

View File

@ -10,7 +10,6 @@ use reqwest::Client;
use serde::Serialize; use serde::Serialize;
pub mod chat_server; pub mod chat_server;
pub mod email;
pub mod handlers; pub mod handlers;
pub mod messages; pub mod messages;
pub mod routes; pub mod routes;

View File

@ -10,6 +10,7 @@ use lemmy_api_common::{
community::CommunityResponse, community::CommunityResponse,
person::PrivateMessageResponse, person::PrivateMessageResponse,
post::PostResponse, post::PostResponse,
send_email_to_user,
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId}, newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
@ -28,14 +29,7 @@ use lemmy_db_views::{
private_message_view::PrivateMessageView, private_message_view::PrivateMessageView,
}; };
use lemmy_db_views_actor::community_view::CommunityView; use lemmy_db_views_actor::community_view::CommunityView;
use lemmy_utils::{ use lemmy_utils::{utils::MentionData, ConnectionId, LemmyError};
email::send_email,
settings::structs::Settings,
utils::MentionData,
ConnectionId,
LemmyError,
};
use tracing::error;
pub async fn send_post_ws_message<OP: ToString + Send + OperationType + 'static>( pub async fn send_post_ws_message<OP: ToString + Send + OperationType + 'static>(
post_id: PostId, post_id: PostId,
@ -296,39 +290,3 @@ pub async fn send_local_notifs(
}; };
Ok(recipient_ids) Ok(recipient_ids)
} }
pub fn send_email_to_user(
local_user_view: &LocalUserView,
subject_text: &str,
body_text: &str,
comment_content: &str,
settings: &Settings,
) {
if local_user_view.person.banned || !local_user_view.local_user.send_notifications_to_email {
return;
}
if let Some(user_email) = &local_user_view.local_user.email {
let subject = &format!(
"{} - {} {}",
subject_text, settings.hostname, local_user_view.person.name,
);
let html = &format!(
"<h1>{}</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
body_text,
local_user_view.person.name,
comment_content,
settings.get_protocol_and_hostname()
);
match send_email(
subject,
user_email,
&local_user_view.person.name,
html,
settings,
) {
Ok(_o) => _o,
Err(e) => error!("{}", e),
};
}
}