]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/local_user.rs
Optimize federated language updates to avoid unnecessary db writes (#2786)
[lemmy.git] / crates / db_schema / src / impls / local_user.rs
1 use crate::{
2   newtypes::LocalUserId,
3   schema::local_user::dsl::{
4     accepted_application,
5     email_verified,
6     local_user,
7     password_encrypted,
8     validator_time,
9   },
10   source::{
11     actor_language::{LocalUserLanguage, SiteLanguage},
12     local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
13   },
14   traits::Crud,
15   utils::{get_conn, naive_now, DbPool},
16 };
17 use bcrypt::{hash, DEFAULT_COST};
18 use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
19 use diesel_async::RunQueryDsl;
20
21 impl LocalUser {
22   pub async fn update_password(
23     pool: &DbPool,
24     local_user_id: LocalUserId,
25     new_password: &str,
26   ) -> Result<Self, Error> {
27     let conn = &mut get_conn(pool).await?;
28     let password_hash = hash(new_password, DEFAULT_COST).expect("Couldn't hash password");
29
30     diesel::update(local_user.find(local_user_id))
31       .set((
32         password_encrypted.eq(password_hash),
33         validator_time.eq(naive_now()),
34       ))
35       .get_result::<Self>(conn)
36       .await
37   }
38
39   pub async fn set_all_users_email_verified(pool: &DbPool) -> Result<Vec<Self>, Error> {
40     let conn = &mut get_conn(pool).await?;
41     diesel::update(local_user)
42       .set(email_verified.eq(true))
43       .get_results::<Self>(conn)
44       .await
45   }
46
47   pub async fn set_all_users_registration_applications_accepted(
48     pool: &DbPool,
49   ) -> Result<Vec<Self>, Error> {
50     let conn = &mut get_conn(pool).await?;
51     diesel::update(local_user)
52       .set(accepted_application.eq(true))
53       .get_results::<Self>(conn)
54       .await
55   }
56 }
57
58 #[async_trait]
59 impl Crud for LocalUser {
60   type InsertForm = LocalUserInsertForm;
61   type UpdateForm = LocalUserUpdateForm;
62   type IdType = LocalUserId;
63   async fn read(pool: &DbPool, local_user_id: LocalUserId) -> Result<Self, Error> {
64     let conn = &mut get_conn(pool).await?;
65     local_user.find(local_user_id).first::<Self>(conn).await
66   }
67   async fn delete(pool: &DbPool, local_user_id: LocalUserId) -> Result<usize, Error> {
68     let conn = &mut get_conn(pool).await?;
69     diesel::delete(local_user.find(local_user_id))
70       .execute(conn)
71       .await
72   }
73   async fn create(pool: &DbPool, form: &Self::InsertForm) -> Result<Self, Error> {
74     let conn = &mut get_conn(pool).await?;
75     let mut form_with_encrypted_password = form.clone();
76     let password_hash =
77       hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
78     form_with_encrypted_password.password_encrypted = password_hash;
79
80     let local_user_ = insert_into(local_user)
81       .values(form_with_encrypted_password)
82       .get_result::<Self>(conn)
83       .await
84       .expect("couldnt create local user");
85
86     let site_languages = SiteLanguage::read_local_raw(pool).await;
87     if let Ok(langs) = site_languages {
88       // if site exists, init user with site languages
89       LocalUserLanguage::update(pool, langs, local_user_.id).await?;
90     } else {
91       // otherwise, init with all languages (this only happens during tests and
92       // for first admin user, which is created before site)
93       LocalUserLanguage::update(pool, vec![], local_user_.id).await?;
94     }
95
96     Ok(local_user_)
97   }
98   async fn update(
99     pool: &DbPool,
100     local_user_id: LocalUserId,
101     form: &Self::UpdateForm,
102   ) -> Result<Self, Error> {
103     let conn = &mut get_conn(pool).await?;
104     diesel::update(local_user.find(local_user_id))
105       .set(form)
106       .get_result::<Self>(conn)
107       .await
108   }
109 }