avoid duplicate writing of new user languages

This commit is contained in:
Felix Ableitner 2024-03-25 12:19:16 +01:00
parent f9d6384e7a
commit 130b803240
17 changed files with 86 additions and 75 deletions

View file

@ -6,10 +6,7 @@ use lemmy_api_common::{
person::GenerateTotpSecretResponse, person::GenerateTotpSecretResponse,
sensitive::Sensitive, sensitive::Sensitive,
}; };
use lemmy_db_schema::{ use lemmy_db_schema::source::local_user::{LocalUser, LocalUserUpdateForm};
source::local_user::{LocalUser, LocalUserUpdateForm},
traits::Crud,
};
use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::error::{LemmyError, LemmyErrorType}; use lemmy_utils::error::{LemmyError, LemmyErrorType};

View file

@ -4,10 +4,7 @@ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
person::{UpdateTotp, UpdateTotpResponse}, person::{UpdateTotp, UpdateTotpResponse},
}; };
use lemmy_db_schema::{ use lemmy_db_schema::source::local_user::{LocalUser, LocalUserUpdateForm};
source::local_user::{LocalUser, LocalUserUpdateForm},
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView; use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyError; use lemmy_utils::error::LemmyError;

View file

@ -124,7 +124,9 @@ mod tests {
.password_encrypted("123456".to_string()) .password_encrypted("123456".to_string())
.build(); .build();
let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![])
.await
.unwrap();
let req = TestRequest::default().to_http_request(); let req = TestRequest::default().to_http_request();
let jwt = Claims::generate(inserted_local_user.id, req, &context) let jwt = Claims::generate(inserted_local_user.id, req, &context)

View file

@ -19,7 +19,6 @@ use lemmy_api_common::{
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PersonAggregates, aggregates::structs::PersonAggregates,
source::{ source::{
actor_language::LocalUserLanguage,
captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer}, captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer},
language::Language, language::Language,
local_user::{LocalUser, LocalUserInsertForm}, local_user::{LocalUser, LocalUserInsertForm},
@ -155,8 +154,6 @@ pub async fn register(
.admin(Some(!local_site.site_setup)) .admin(Some(!local_site.site_setup))
.build(); .build();
let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?;
let all_languages = Language::read_all(&mut context.pool()).await?; let all_languages = Language::read_all(&mut context.pool()).await?;
// use hashset to avoid duplicates // use hashset to avoid duplicates
let mut language_ids = HashSet::new(); let mut language_ids = HashSet::new();
@ -166,7 +163,9 @@ pub async fn register(
} }
} }
let language_ids = language_ids.into_iter().collect(); let language_ids = language_ids.into_iter().collect();
LocalUserLanguage::update(&mut context.pool(), language_ids, inserted_local_user.id).await?;
let inserted_local_user =
LocalUser::create(&mut context.pool(), &local_user_form, language_ids).await?;
if local_site.site_setup && require_registration_application { if local_site.site_setup && require_registration_application {
// Create the registration application // Create the registration application

View file

@ -361,7 +361,7 @@ mod tests {
.person_id(person.id) .person_id(person.id)
.password_encrypted("pass".to_string()) .password_encrypted("pass".to_string())
.build(); .build();
let local_user = LocalUser::create(&mut context.pool(), &user_form).await?; let local_user = LocalUser::create(&mut context.pool(), &user_form, vec![]).await?;
Ok(LocalUserView::read(&mut context.pool(), local_user.id).await?) Ok(LocalUserView::read(&mut context.pool(), local_user.id).await?)
} }

View file

@ -535,7 +535,9 @@ mod tests {
.password_encrypted("my_pw".to_string()) .password_encrypted("my_pw".to_string())
.build(); .build();
let local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); let local_user = LocalUser::create(pool, &local_user_form, vec![])
.await
.unwrap();
let local_user_langs1 = LocalUserLanguage::read(pool, local_user.id).await.unwrap(); let local_user_langs1 = LocalUserLanguage::read(pool, local_user.id).await.unwrap();
// new user should be initialized with all languages // new user should be initialized with all languages
@ -648,7 +650,9 @@ mod tests {
.person_id(person.id) .person_id(person.id)
.password_encrypted("my_pw".to_string()) .password_encrypted("my_pw".to_string())
.build(); .build();
let local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); let local_user = LocalUser::create(pool, &local_user_form, vec![])
.await
.unwrap();
LocalUserLanguage::update(pool, test_langs2, local_user.id) LocalUserLanguage::update(pool, test_langs2, local_user.id)
.await .await
.unwrap(); .unwrap();

View file

@ -1,12 +1,11 @@
use crate::{ use crate::{
newtypes::{DbUrl, LocalUserId, PersonId}, newtypes::{DbUrl, LanguageId, LocalUserId, PersonId},
schema::{local_user, person, registration_application}, schema::{local_user, person, registration_application},
source::{ source::{
actor_language::LocalUserLanguage, actor_language::LocalUserLanguage,
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm}, local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeInsertForm}, local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeInsertForm},
}, },
traits::Crud,
utils::{ utils::{
functions::{coalesce, lower}, functions::{coalesce, lower},
get_conn, get_conn,
@ -25,6 +24,52 @@ use diesel::{
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
impl LocalUser { impl LocalUser {
pub async fn create(
pool: &mut DbPool<'_>,
form: &LocalUserInsertForm,
languages: Vec<LanguageId>,
) -> Result<LocalUser, Error> {
let conn = &mut get_conn(pool).await?;
let mut form_with_encrypted_password = form.clone();
let password_hash =
hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
form_with_encrypted_password.password_encrypted = password_hash;
let local_user_ = insert_into(local_user::table)
.values(form_with_encrypted_password)
.get_result::<Self>(conn)
.await?;
LocalUserLanguage::update(pool, languages, local_user_.id).await?;
// Create their vote_display_modes
let vote_display_mode_form = LocalUserVoteDisplayModeInsertForm::builder()
.local_user_id(local_user_.id)
.build();
LocalUserVoteDisplayMode::create(pool, &vote_display_mode_form).await?;
Ok(local_user_)
}
pub async fn update(
pool: &mut DbPool<'_>,
local_user_id: LocalUserId,
form: &LocalUserUpdateForm,
) -> Result<LocalUser, Error> {
let conn = &mut get_conn(pool).await?;
diesel::update(local_user::table.find(local_user_id))
.set(form)
.get_result::<Self>(conn)
.await
}
pub async fn delete(pool: &mut DbPool<'_>, id: LocalUserId) -> Result<usize, Error> {
let conn = &mut *get_conn(pool).await?;
diesel::delete(local_user::table.find(id))
.execute(conn)
.await
}
pub async fn update_password( pub async fn update_password(
pool: &mut DbPool<'_>, pool: &mut DbPool<'_>,
local_user_id: LocalUserId, local_user_id: LocalUserId,
@ -183,47 +228,3 @@ pub struct UserBackupLists {
pub blocked_users: Vec<DbUrl>, pub blocked_users: Vec<DbUrl>,
pub blocked_instances: Vec<String>, pub blocked_instances: Vec<String>,
} }
#[async_trait]
impl Crud for LocalUser {
type InsertForm = LocalUserInsertForm;
type UpdateForm = LocalUserUpdateForm;
type IdType = LocalUserId;
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
let mut form_with_encrypted_password = form.clone();
let password_hash =
hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
form_with_encrypted_password.password_encrypted = password_hash;
let local_user_ = insert_into(local_user::table)
.values(form_with_encrypted_password)
.get_result::<Self>(conn)
.await?;
// TODO: this is necessary for tests, but causes unnecessary db writes in production as languages
// are set from accept-language header immediately after. would be good if final languages
// could be passed in directly.
LocalUserLanguage::update(pool, vec![], local_user_.id).await?;
// Create their vote_display_modes
let vote_display_mode_form = LocalUserVoteDisplayModeInsertForm::builder()
.local_user_id(local_user_.id)
.build();
LocalUserVoteDisplayMode::create(pool, &vote_display_mode_form).await?;
Ok(local_user_)
}
async fn update(
pool: &mut DbPool<'_>,
local_user_id: LocalUserId,
form: &Self::UpdateForm,
) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
diesel::update(local_user::table.find(local_user_id))
.set(form)
.get_result::<Self>(conn)
.await
}
}

View file

@ -121,7 +121,9 @@ mod tests {
.password_encrypted("pass".to_string()) .password_encrypted("pass".to_string())
.build(); .build();
let inserted_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); let inserted_local_user = LocalUser::create(pool, &new_local_user, vec![])
.await
.unwrap();
let token = "nope"; let token = "nope";

View file

@ -308,7 +308,9 @@ mod tests {
.person_id(inserted_timmy.id) .person_id(inserted_timmy.id)
.password_encrypted("123".to_string()) .password_encrypted("123".to_string())
.build(); .build();
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); let timmy_local_user = LocalUser::create(pool, &new_local_user, vec![])
.await
.unwrap();
let timmy_view = LocalUserView { let timmy_view = LocalUserView {
local_user: timmy_local_user, local_user: timmy_local_user,
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(), local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),

View file

@ -481,7 +481,7 @@ mod tests {
.admin(Some(true)) .admin(Some(true))
.password_encrypted(String::new()) .password_encrypted(String::new())
.build(); .build();
let inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form) let inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![])
.await .await
.unwrap(); .unwrap();

View file

@ -330,7 +330,9 @@ mod tests {
.person_id(inserted_timmy.id) .person_id(inserted_timmy.id)
.password_encrypted("123".to_string()) .password_encrypted("123".to_string())
.build(); .build();
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); let timmy_local_user = LocalUser::create(pool, &new_local_user, vec![])
.await
.unwrap();
let timmy_view = LocalUserView { let timmy_view = LocalUserView {
local_user: timmy_local_user, local_user: timmy_local_user,
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(), local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),

View file

@ -807,7 +807,7 @@ mod tests {
admin: Some(true), admin: Some(true),
..LocalUserInsertForm::test_form(inserted_person.id) ..LocalUserInsertForm::test_form(inserted_person.id)
}; };
let inserted_local_user = LocalUser::create(pool, &local_user_form).await?; let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![]).await?;
let new_bot = PersonInsertForm { let new_bot = PersonInsertForm {
bot_account: Some(true), bot_account: Some(true),
@ -833,6 +833,7 @@ mod tests {
let inserted_blocked_local_user = LocalUser::create( let inserted_blocked_local_user = LocalUser::create(
pool, pool,
&LocalUserInsertForm::test_form(inserted_blocked_person.id), &LocalUserInsertForm::test_form(inserted_blocked_person.id),
vec![],
) )
.await?; .await?;

View file

@ -176,7 +176,7 @@ mod tests {
.admin(Some(true)) .admin(Some(true))
.build(); .build();
let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form) let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![])
.await .await
.unwrap(); .unwrap();
@ -193,7 +193,7 @@ mod tests {
.password_encrypted("nada".to_string()) .password_encrypted("nada".to_string())
.build(); .build();
let inserted_sara_local_user = LocalUser::create(pool, &sara_local_user_form) let inserted_sara_local_user = LocalUser::create(pool, &sara_local_user_form, vec![])
.await .await
.unwrap(); .unwrap();
@ -224,7 +224,7 @@ mod tests {
.password_encrypted("nada".to_string()) .password_encrypted("nada".to_string())
.build(); .build();
let inserted_jess_local_user = LocalUser::create(pool, &jess_local_user_form) let inserted_jess_local_user = LocalUser::create(pool, &jess_local_user_form, vec![])
.await .await
.unwrap(); .unwrap();

View file

@ -296,7 +296,9 @@ mod tests {
.person_id(inserted_person.id) .person_id(inserted_person.id)
.password_encrypted(String::new()) .password_encrypted(String::new())
.build(); .build();
let local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); let local_user = LocalUser::create(pool, &local_user_form, vec![])
.await
.unwrap();
let new_community = CommunityInsertForm::builder() let new_community = CommunityInsertForm::builder()
.name("test_community_3".to_string()) .name("test_community_3".to_string())

View file

@ -204,7 +204,7 @@ mod tests {
.person_id(alice.id) .person_id(alice.id)
.password_encrypted(String::new()) .password_encrypted(String::new())
.build(); .build();
let alice_local_user = LocalUser::create(pool, &alice_local_user_form).await?; let alice_local_user = LocalUser::create(pool, &alice_local_user_form, vec![]).await?;
let bob_form = PersonInsertForm::builder() let bob_form = PersonInsertForm::builder()
.name("bob".to_string()) .name("bob".to_string())
@ -218,7 +218,7 @@ mod tests {
.person_id(bob.id) .person_id(bob.id)
.password_encrypted(String::new()) .password_encrypted(String::new())
.build(); .build();
let bob_local_user = LocalUser::create(pool, &bob_local_user_form).await?; let bob_local_user = LocalUser::create(pool, &bob_local_user_form, vec![]).await?;
Ok(Data { Ok(Data {
alice, alice,

View file

@ -475,7 +475,7 @@ async fn initialize_local_site_2022_10_10(
.email(setup.admin_email.clone()) .email(setup.admin_email.clone())
.admin(Some(true)) .admin(Some(true))
.build(); .build();
LocalUser::create(pool, &local_user_form).await?; LocalUser::create(pool, &local_user_form, vec![]).await?;
}; };
// Add an entry for the site table // Add an entry for the site table

View file

@ -155,7 +155,9 @@ mod tests {
.password_encrypted("123456".to_string()) .password_encrypted("123456".to_string())
.build(); .build();
let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap(); let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![])
.await
.unwrap();
let req = TestRequest::default().to_http_request(); let req = TestRequest::default().to_http_request();
let jwt = Claims::generate(inserted_local_user.id, req, &context) let jwt = Claims::generate(inserted_local_user.id, req, &context)