Adding email admins for new applications. Fixes #2271 (#2390)

* Adding email admins for new applications. Fixes #2271

* Fix error.

Co-authored-by: Nutomic <me@nutomic.com>
This commit is contained in:
Dessalines 2022-09-27 12:48:44 -04:00 committed by GitHub
parent 0aeb78b8f3
commit ae95f5928e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 94 additions and 6 deletions

View file

@ -125,6 +125,7 @@ pub struct CreateSite {
pub private_instance: Option<bool>, pub private_instance: Option<bool>,
pub default_theme: Option<String>, pub default_theme: Option<String>,
pub default_post_listing_type: Option<String>, pub default_post_listing_type: Option<String>,
pub application_email_admins: Option<bool>,
pub auth: Sensitive<String>, pub auth: Sensitive<String>,
pub hide_modlog_mod_names: Option<bool>, pub hide_modlog_mod_names: Option<bool>,
} }
@ -147,6 +148,7 @@ pub struct EditSite {
pub default_theme: Option<String>, pub default_theme: Option<String>,
pub default_post_listing_type: Option<String>, pub default_post_listing_type: Option<String>,
pub legal_information: Option<String>, pub legal_information: Option<String>,
pub application_email_admins: Option<bool>,
pub auth: Sensitive<String>, pub auth: Sensitive<String>,
pub hide_modlog_mod_names: Option<bool>, pub hide_modlog_mod_names: Option<bool>,
} }

View file

@ -452,8 +452,16 @@ pub fn send_email_verification_success(
} }
pub fn get_interface_language(user: &LocalUserView) -> Lang { pub fn get_interface_language(user: &LocalUserView) -> Lang {
let user_lang = LanguageId::new(user.local_user.interface_language.clone()); lang_str_to_lang(&user.local_user.interface_language)
Lang::from_language_id(&user_lang).unwrap_or_else(|| { }
pub fn get_interface_language_from_settings(user: &LocalUserSettingsView) -> Lang {
lang_str_to_lang(&user.local_user.interface_language)
}
fn lang_str_to_lang(lang: &str) -> Lang {
let lang_id = LanguageId::new(lang);
Lang::from_language_id(&lang_id).unwrap_or_else(|| {
let en = LanguageId::new("en"); let en = LanguageId::new("en");
Lang::from_language_id(&en).expect("default language") Lang::from_language_id(&en).expect("default language")
}) })
@ -470,6 +478,33 @@ pub fn send_application_approved_email(
send_email(&subject, email, &user.person.name, &body, settings) send_email(&subject, email, &user.person.name, &body, settings)
} }
/// Send a new applicant email notification to all admins
pub async fn send_new_applicant_email_to_admins(
applicant_username: &str,
pool: &DbPool,
settings: &Settings,
) -> Result<(), LemmyError> {
// Collect the admins with emails
let admins = blocking(pool, move |conn| {
LocalUserSettingsView::list_admins_with_emails(conn)
})
.await??;
let applications_link = &format!(
"{}/registration_applications",
settings.get_protocol_and_hostname(),
);
for admin in &admins {
let email = &admin.local_user.email.to_owned().expect("email");
let lang = get_interface_language_from_settings(admin);
let subject = lang.new_application_subject(applicant_username, &settings.hostname);
let body = lang.new_application_body(applications_link);
send_email(&subject, email, &admin.person.name, &body, settings)?;
}
Ok(())
}
pub async fn check_registration_application( pub async fn check_registration_application(
site: &Site, site: &Site,
local_user_view: &LocalUserView, local_user_view: &LocalUserView,

View file

@ -76,6 +76,7 @@ impl PerformCrud for CreateSite {
public_key: Some(keypair.public_key), public_key: Some(keypair.public_key),
default_theme: data.default_theme.clone(), default_theme: data.default_theme.clone(),
default_post_listing_type: data.default_post_listing_type.clone(), default_post_listing_type: data.default_post_listing_type.clone(),
application_email_admins: data.application_email_admins,
hide_modlog_mod_names: data.hide_modlog_mod_names, hide_modlog_mod_names: data.hide_modlog_mod_names,
..SiteForm::default() ..SiteForm::default()
}; };

View file

@ -86,6 +86,7 @@ impl PerformCrud for EditSite {
default_theme: data.default_theme.clone(), default_theme: data.default_theme.clone(),
default_post_listing_type: data.default_post_listing_type.clone(), default_post_listing_type: data.default_post_listing_type.clone(),
legal_information, legal_information,
application_email_admins: data.application_email_admins,
hide_modlog_mod_names: data.hide_modlog_mod_names, hide_modlog_mod_names: data.hide_modlog_mod_names,
..SiteForm::default() ..SiteForm::default()
}; };

View file

@ -3,7 +3,13 @@ use activitypub_federation::core::signatures::generate_actor_keypair;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{ use lemmy_api_common::{
person::{LoginResponse, Register}, person::{LoginResponse, Register},
utils::{blocking, honeypot_check, password_length_check, send_verification_email}, utils::{
blocking,
honeypot_check,
password_length_check,
send_new_applicant_email_to_admins,
send_verification_email,
},
}; };
use lemmy_apub::{ use lemmy_apub::{
generate_inbox_url, generate_inbox_url,
@ -47,7 +53,8 @@ impl PerformCrud for Register {
let (mut email_verification, mut require_application) = (false, false); let (mut email_verification, mut require_application) = (false, false);
// Make sure site has open registration // Make sure site has open registration
if let Ok(site) = blocking(context.pool(), Site::read_local_site).await? { let site = blocking(context.pool(), Site::read_local_site).await?;
if let Ok(site) = &site {
if !site.open_registration { if !site.open_registration {
return Err(LemmyError::from_message("registration_closed")); return Err(LemmyError::from_message("registration_closed"));
} }
@ -184,6 +191,12 @@ impl PerformCrud for Register {
.await??; .await??;
} }
// Email the admins
if site.map(|s| s.application_email_admins).unwrap_or(false) {
send_new_applicant_email_to_admins(&data.username, context.pool(), context.settings())
.await?;
}
let mut login_response = LoginResponse { let mut login_response = LoginResponse {
jwt: None, jwt: None,
registration_created: false, registration_created: false,

View file

@ -504,6 +504,7 @@ table! {
default_theme -> Text, default_theme -> Text,
default_post_listing_type -> Text, default_post_listing_type -> Text,
legal_information -> Nullable<Text>, legal_information -> Nullable<Text>,
application_email_admins -> Bool,
hide_modlog_mod_names -> Bool, hide_modlog_mod_names -> Bool,
} }
} }

View file

@ -32,6 +32,7 @@ pub struct Site {
pub default_theme: String, pub default_theme: String,
pub default_post_listing_type: String, pub default_post_listing_type: String,
pub legal_information: Option<String>, pub legal_information: Option<String>,
pub application_email_admins: bool,
pub hide_modlog_mod_names: bool, pub hide_modlog_mod_names: bool,
} }
@ -62,5 +63,6 @@ pub struct SiteForm {
pub default_theme: Option<String>, pub default_theme: Option<String>,
pub default_post_listing_type: Option<String>, pub default_post_listing_type: Option<String>,
pub legal_information: Option<Option<String>>, pub legal_information: Option<Option<String>>,
pub application_email_admins: Option<bool>,
pub hide_modlog_mod_names: Option<bool>, pub hide_modlog_mod_names: Option<bool>,
} }

View file

@ -8,7 +8,7 @@ use lemmy_db_schema::{
local_user::{LocalUser, LocalUserSettings}, local_user::{LocalUser, LocalUserSettings},
person::{Person, PersonSafe}, person::{Person, PersonSafe},
}, },
traits::{ToSafe, ToSafeSettings}, traits::{ToSafe, ToSafeSettings, ViewToVec},
utils::functions::lower, utils::functions::lower,
}; };
@ -134,4 +134,34 @@ impl LocalUserSettingsView {
counts, counts,
}) })
} }
pub fn list_admins_with_emails(conn: &mut PgConnection) -> Result<Vec<Self>, Error> {
let res = local_user::table
.filter(person::admin.eq(true))
.filter(local_user::email.is_not_null())
.inner_join(person::table)
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
.select((
LocalUser::safe_settings_columns_tuple(),
Person::safe_columns_tuple(),
person_aggregates::all_columns,
))
.load::<LocalUserSettingsViewTuple>(conn)?;
Ok(LocalUserSettingsView::from_tuple_to_vec(res))
}
}
impl ViewToVec for LocalUserSettingsView {
type DbTuple = LocalUserSettingsViewTuple;
fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
items
.into_iter()
.map(|a| Self {
local_user: a.0,
person: a.1,
counts: a.2,
})
.collect::<Vec<Self>>()
}
} }

@ -1 +1 @@
Subproject commit 3f86b5c40796fa83054e2226e36effff3b93198a Subproject commit f5d6f0eabafd559417bf8f203fd655f7858bffcf

View file

@ -0,0 +1 @@
alter table site drop column application_email_admins;

View file

@ -0,0 +1,2 @@
-- Adding a field to email admins for new applications
alter table site add column application_email_admins boolean not null default false;