]> Untitled Git - lemmy.git/blob - server/lemmy_db/src/user.rs
Translated using Weblate (Italian)
[lemmy.git] / server / lemmy_db / src / user.rs
1 use crate::{
2   is_email_regex,
3   naive_now,
4   schema::{user_, user_::dsl::*},
5   Crud,
6 };
7 use bcrypt::{hash, DEFAULT_COST};
8 use diesel::{dsl::*, result::Error, *};
9 use serde::{Deserialize, Serialize};
10
11 #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
12 #[table_name = "user_"]
13 pub struct User_ {
14   pub id: i32,
15   pub name: String,
16   pub preferred_username: Option<String>,
17   pub password_encrypted: String,
18   pub email: Option<String>,
19   pub avatar: Option<String>,
20   pub admin: bool,
21   pub banned: bool,
22   pub published: chrono::NaiveDateTime,
23   pub updated: Option<chrono::NaiveDateTime>,
24   pub show_nsfw: bool,
25   pub theme: String,
26   pub default_sort_type: i16,
27   pub default_listing_type: i16,
28   pub lang: String,
29   pub show_avatars: bool,
30   pub send_notifications_to_email: bool,
31   pub matrix_user_id: Option<String>,
32   pub actor_id: String,
33   pub bio: Option<String>,
34   pub local: bool,
35   pub private_key: Option<String>,
36   pub public_key: Option<String>,
37   pub last_refreshed_at: chrono::NaiveDateTime,
38 }
39
40 #[derive(Insertable, AsChangeset, Clone, Debug)]
41 #[table_name = "user_"]
42 pub struct UserForm {
43   pub name: String,
44   pub preferred_username: Option<String>,
45   pub password_encrypted: String,
46   pub admin: bool,
47   pub banned: bool,
48   pub email: Option<String>,
49   pub avatar: Option<String>,
50   pub updated: Option<chrono::NaiveDateTime>,
51   pub show_nsfw: bool,
52   pub theme: String,
53   pub default_sort_type: i16,
54   pub default_listing_type: i16,
55   pub lang: String,
56   pub show_avatars: bool,
57   pub send_notifications_to_email: bool,
58   pub matrix_user_id: Option<String>,
59   pub actor_id: String,
60   pub bio: Option<String>,
61   pub local: bool,
62   pub private_key: Option<String>,
63   pub public_key: Option<String>,
64   pub last_refreshed_at: Option<chrono::NaiveDateTime>,
65 }
66
67 impl Crud<UserForm> for User_ {
68   fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
69     user_.find(user_id).first::<Self>(conn)
70   }
71   fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> {
72     diesel::delete(user_.find(user_id)).execute(conn)
73   }
74   fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
75     insert_into(user_).values(form).get_result::<Self>(conn)
76   }
77   fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> {
78     diesel::update(user_.find(user_id))
79       .set(form)
80       .get_result::<Self>(conn)
81   }
82 }
83
84 impl User_ {
85   pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
86     let mut edited_user = form.clone();
87     let password_hash =
88       hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
89     edited_user.password_encrypted = password_hash;
90
91     Self::create(&conn, &edited_user)
92   }
93
94   // TODO do more individual updates like these
95   pub fn update_password(
96     conn: &PgConnection,
97     user_id: i32,
98     new_password: &str,
99   ) -> Result<Self, Error> {
100     let password_hash = hash(new_password, DEFAULT_COST).expect("Couldn't hash password");
101
102     diesel::update(user_.find(user_id))
103       .set((
104         password_encrypted.eq(password_hash),
105         updated.eq(naive_now()),
106       ))
107       .get_result::<Self>(conn)
108   }
109
110   pub fn read_from_name(conn: &PgConnection, from_user_name: &str) -> Result<Self, Error> {
111     user_.filter(name.eq(from_user_name)).first::<Self>(conn)
112   }
113
114   pub fn add_admin(conn: &PgConnection, user_id: i32, added: bool) -> Result<Self, Error> {
115     diesel::update(user_.find(user_id))
116       .set(admin.eq(added))
117       .get_result::<Self>(conn)
118   }
119
120   pub fn ban_user(conn: &PgConnection, user_id: i32, ban: bool) -> Result<Self, Error> {
121     diesel::update(user_.find(user_id))
122       .set(banned.eq(ban))
123       .get_result::<Self>(conn)
124   }
125
126   pub fn read_from_actor_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
127     use crate::schema::user_::dsl::*;
128     user_.filter(actor_id.eq(object_id)).first::<Self>(conn)
129   }
130
131   pub fn find_by_email_or_username(
132     conn: &PgConnection,
133     username_or_email: &str,
134   ) -> Result<Self, Error> {
135     if is_email_regex(username_or_email) {
136       Self::find_by_email(conn, username_or_email)
137     } else {
138       Self::find_by_username(conn, username_or_email)
139     }
140   }
141
142   pub fn find_by_username(conn: &PgConnection, username: &str) -> Result<User_, Error> {
143     user_.filter(name.eq(username)).first::<User_>(conn)
144   }
145
146   pub fn find_by_email(conn: &PgConnection, from_email: &str) -> Result<User_, Error> {
147     user_.filter(email.eq(from_email)).first::<User_>(conn)
148   }
149
150   pub fn get_profile_url(&self, hostname: &str) -> String {
151     format!("https://{}/u/{}", hostname, self.name)
152   }
153 }
154
155 #[cfg(test)]
156 mod tests {
157   use crate::{tests::establish_unpooled_connection, user::*, ListingType, SortType};
158
159   #[test]
160   fn test_crud() {
161     let conn = establish_unpooled_connection();
162
163     let new_user = UserForm {
164       name: "thommy".into(),
165       preferred_username: None,
166       password_encrypted: "nope".into(),
167       email: None,
168       matrix_user_id: None,
169       avatar: None,
170       admin: false,
171       banned: false,
172       updated: None,
173       show_nsfw: false,
174       theme: "darkly".into(),
175       default_sort_type: SortType::Hot as i16,
176       default_listing_type: ListingType::Subscribed as i16,
177       lang: "browser".into(),
178       show_avatars: true,
179       send_notifications_to_email: false,
180       actor_id: "changeme_9826382637".into(),
181       bio: None,
182       local: true,
183       private_key: None,
184       public_key: None,
185       last_refreshed_at: None,
186     };
187
188     let inserted_user = User_::create(&conn, &new_user).unwrap();
189
190     let expected_user = User_ {
191       id: inserted_user.id,
192       name: "thommy".into(),
193       preferred_username: None,
194       password_encrypted: "nope".into(),
195       email: None,
196       matrix_user_id: None,
197       avatar: None,
198       admin: false,
199       banned: false,
200       published: inserted_user.published,
201       updated: None,
202       show_nsfw: false,
203       theme: "darkly".into(),
204       default_sort_type: SortType::Hot as i16,
205       default_listing_type: ListingType::Subscribed as i16,
206       lang: "browser".into(),
207       show_avatars: true,
208       send_notifications_to_email: false,
209       actor_id: inserted_user.actor_id.to_owned(),
210       bio: None,
211       local: true,
212       private_key: None,
213       public_key: None,
214       last_refreshed_at: inserted_user.published,
215     };
216
217     let read_user = User_::read(&conn, inserted_user.id).unwrap();
218     let updated_user = User_::update(&conn, inserted_user.id, &new_user).unwrap();
219     let num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
220
221     assert_eq!(expected_user, read_user);
222     assert_eq!(expected_user, inserted_user);
223     assert_eq!(expected_user, updated_user);
224     assert_eq!(1, num_deleted);
225   }
226 }