From ae95f5928e68b8303834c784f955269e6930f28f Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 27 Sep 2022 12:48:44 -0400 Subject: [PATCH] Adding email admins for new applications. Fixes #2271 (#2390) * Adding email admins for new applications. Fixes #2271 * Fix error. Co-authored-by: Nutomic --- crates/api_common/src/site.rs | 2 + crates/api_common/src/utils.rs | 39 ++++++++++++++++++- crates/api_crud/src/site/create.rs | 1 + crates/api_crud/src/site/update.rs | 1 + crates/api_crud/src/user/create.rs | 17 +++++++- crates/db_schema/src/schema.rs | 1 + crates/db_schema/src/source/site.rs | 2 + crates/db_views/src/local_user_view.rs | 32 ++++++++++++++- crates/utils/translations | 2 +- .../down.sql | 1 + .../up.sql | 2 + 11 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 migrations/2022-08-04-150644_add_application_email_admins/down.sql create mode 100644 migrations/2022-08-04-150644_add_application_email_admins/up.sql diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index eb520e29e..953afceca 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -125,6 +125,7 @@ pub struct CreateSite { pub private_instance: Option, pub default_theme: Option, pub default_post_listing_type: Option, + pub application_email_admins: Option, pub auth: Sensitive, pub hide_modlog_mod_names: Option, } @@ -147,6 +148,7 @@ pub struct EditSite { pub default_theme: Option, pub default_post_listing_type: Option, pub legal_information: Option, + pub application_email_admins: Option, pub auth: Sensitive, pub hide_modlog_mod_names: Option, } diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index ce6831e39..ba776002f 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -452,8 +452,16 @@ pub fn send_email_verification_success( } pub fn get_interface_language(user: &LocalUserView) -> Lang { - let user_lang = LanguageId::new(user.local_user.interface_language.clone()); - Lang::from_language_id(&user_lang).unwrap_or_else(|| { + lang_str_to_lang(&user.local_user.interface_language) +} + +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"); 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 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( site: &Site, local_user_view: &LocalUserView, diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index d74117f43..2eaea2510 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -76,6 +76,7 @@ impl PerformCrud for CreateSite { public_key: Some(keypair.public_key), default_theme: data.default_theme.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, ..SiteForm::default() }; diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index e5a56468b..e2be3bc10 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -86,6 +86,7 @@ impl PerformCrud for EditSite { default_theme: data.default_theme.clone(), default_post_listing_type: data.default_post_listing_type.clone(), legal_information, + application_email_admins: data.application_email_admins, hide_modlog_mod_names: data.hide_modlog_mod_names, ..SiteForm::default() }; diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 9529d8a5a..80100a25d 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -3,7 +3,13 @@ use activitypub_federation::core::signatures::generate_actor_keypair; use actix_web::web::Data; use lemmy_api_common::{ 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::{ generate_inbox_url, @@ -47,7 +53,8 @@ impl PerformCrud for Register { let (mut email_verification, mut require_application) = (false, false); // 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 { return Err(LemmyError::from_message("registration_closed")); } @@ -184,6 +191,12 @@ impl PerformCrud for Register { .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 { jwt: None, registration_created: false, diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index d7f477b7f..8fa98270a 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -504,6 +504,7 @@ table! { default_theme -> Text, default_post_listing_type -> Text, legal_information -> Nullable, + application_email_admins -> Bool, hide_modlog_mod_names -> Bool, } } diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs index 82876d837..5260cc2de 100644 --- a/crates/db_schema/src/source/site.rs +++ b/crates/db_schema/src/source/site.rs @@ -32,6 +32,7 @@ pub struct Site { pub default_theme: String, pub default_post_listing_type: String, pub legal_information: Option, + pub application_email_admins: bool, pub hide_modlog_mod_names: bool, } @@ -62,5 +63,6 @@ pub struct SiteForm { pub default_theme: Option, pub default_post_listing_type: Option, pub legal_information: Option>, + pub application_email_admins: Option, pub hide_modlog_mod_names: Option, } diff --git a/crates/db_views/src/local_user_view.rs b/crates/db_views/src/local_user_view.rs index 0e6d24b11..b5a758b84 100644 --- a/crates/db_views/src/local_user_view.rs +++ b/crates/db_views/src/local_user_view.rs @@ -8,7 +8,7 @@ use lemmy_db_schema::{ local_user::{LocalUser, LocalUserSettings}, person::{Person, PersonSafe}, }, - traits::{ToSafe, ToSafeSettings}, + traits::{ToSafe, ToSafeSettings, ViewToVec}, utils::functions::lower, }; @@ -134,4 +134,34 @@ impl LocalUserSettingsView { counts, }) } + + pub fn list_admins_with_emails(conn: &mut PgConnection) -> Result, 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::(conn)?; + + Ok(LocalUserSettingsView::from_tuple_to_vec(res)) + } +} + +impl ViewToVec for LocalUserSettingsView { + type DbTuple = LocalUserSettingsViewTuple; + fn from_tuple_to_vec(items: Vec) -> Vec { + items + .into_iter() + .map(|a| Self { + local_user: a.0, + person: a.1, + counts: a.2, + }) + .collect::>() + } } diff --git a/crates/utils/translations b/crates/utils/translations index 3f86b5c40..f5d6f0eab 160000 --- a/crates/utils/translations +++ b/crates/utils/translations @@ -1 +1 @@ -Subproject commit 3f86b5c40796fa83054e2226e36effff3b93198a +Subproject commit f5d6f0eabafd559417bf8f203fd655f7858bffcf diff --git a/migrations/2022-08-04-150644_add_application_email_admins/down.sql b/migrations/2022-08-04-150644_add_application_email_admins/down.sql new file mode 100644 index 000000000..c515275ae --- /dev/null +++ b/migrations/2022-08-04-150644_add_application_email_admins/down.sql @@ -0,0 +1 @@ +alter table site drop column application_email_admins; diff --git a/migrations/2022-08-04-150644_add_application_email_admins/up.sql b/migrations/2022-08-04-150644_add_application_email_admins/up.sql new file mode 100644 index 000000000..adf8f3c11 --- /dev/null +++ b/migrations/2022-08-04-150644_add_application_email_admins/up.sql @@ -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;