]> Untitled Git - lemmy.git/blob - server/src/db/user.rs
Spanish translations
[lemmy.git] / server / src / db / user.rs
1 use super::*;
2 use crate::schema::user_;
3 use crate::schema::user_::dsl::*;
4 use crate::{is_email_regex, Settings};
5 use bcrypt::{hash, DEFAULT_COST};
6 use jsonwebtoken::{decode, encode, Header, TokenData, Validation};
7
8 #[derive(Queryable, Identifiable, PartialEq, Debug)]
9 #[table_name = "user_"]
10 pub struct User_ {
11   pub id: i32,
12   pub name: String,
13   pub fedi_name: String,
14   pub preferred_username: Option<String>,
15   pub password_encrypted: String,
16   pub email: Option<String>,
17   pub icon: Option<Vec<u8>>,
18   pub admin: bool,
19   pub banned: bool,
20   pub published: chrono::NaiveDateTime,
21   pub updated: Option<chrono::NaiveDateTime>,
22   pub show_nsfw: bool,
23   pub theme: String,
24 }
25
26 #[derive(Insertable, AsChangeset, Clone)]
27 #[table_name = "user_"]
28 pub struct UserForm {
29   pub name: String,
30   pub fedi_name: String,
31   pub preferred_username: Option<String>,
32   pub password_encrypted: String,
33   pub admin: bool,
34   pub banned: bool,
35   pub email: Option<String>,
36   pub updated: Option<chrono::NaiveDateTime>,
37   pub show_nsfw: bool,
38   pub theme: String,
39 }
40
41 impl Crud<UserForm> for User_ {
42   fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
43     use crate::schema::user_::dsl::*;
44     user_.find(user_id).first::<Self>(conn)
45   }
46   fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> {
47     diesel::delete(user_.find(user_id)).execute(conn)
48   }
49   fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
50     insert_into(user_).values(form).get_result::<Self>(conn)
51   }
52   fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> {
53     diesel::update(user_.find(user_id))
54       .set(form)
55       .get_result::<Self>(conn)
56   }
57 }
58
59 impl User_ {
60   pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
61     let mut edited_user = form.clone();
62     let password_hash =
63       hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
64     edited_user.password_encrypted = password_hash;
65
66     Self::create(&conn, &edited_user)
67   }
68   pub fn read_from_name(conn: &PgConnection, from_user_name: String) -> Result<Self, Error> {
69     user_.filter(name.eq(from_user_name)).first::<Self>(conn)
70   }
71 }
72
73 #[derive(Debug, Serialize, Deserialize)]
74 pub struct Claims {
75   pub id: i32,
76   pub username: String,
77   pub iss: String,
78   pub show_nsfw: bool,
79   pub theme: String,
80 }
81
82 impl Claims {
83   pub fn decode(jwt: &str) -> Result<TokenData<Claims>, jsonwebtoken::errors::Error> {
84     let v = Validation {
85       validate_exp: false,
86       ..Validation::default()
87     };
88     decode::<Claims>(&jwt, Settings::get().jwt_secret.as_ref(), &v)
89   }
90 }
91
92 type Jwt = String;
93 impl User_ {
94   pub fn jwt(&self) -> Jwt {
95     let my_claims = Claims {
96       id: self.id,
97       username: self.name.to_owned(),
98       iss: self.fedi_name.to_owned(),
99       show_nsfw: self.show_nsfw,
100       theme: self.theme.to_owned(),
101     };
102     encode(
103       &Header::default(),
104       &my_claims,
105       Settings::get().jwt_secret.as_ref(),
106     )
107     .unwrap()
108   }
109
110   pub fn find_by_email_or_username(
111     conn: &PgConnection,
112     username_or_email: &str,
113   ) -> Result<Self, Error> {
114     if is_email_regex(username_or_email) {
115       user_
116         .filter(email.eq(username_or_email))
117         .first::<User_>(conn)
118     } else {
119       user_
120         .filter(name.eq(username_or_email))
121         .first::<User_>(conn)
122     }
123   }
124
125   pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> {
126     let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims;
127     Self::read(&conn, claims.id)
128   }
129 }
130
131 #[cfg(test)]
132 mod tests {
133   use super::*;
134   #[test]
135   fn test_crud() {
136     let conn = establish_connection();
137
138     let new_user = UserForm {
139       name: "thommy".into(),
140       fedi_name: "rrf".into(),
141       preferred_username: None,
142       password_encrypted: "nope".into(),
143       email: None,
144       admin: false,
145       banned: false,
146       updated: None,
147       show_nsfw: false,
148       theme: "darkly".into(),
149     };
150
151     let inserted_user = User_::create(&conn, &new_user).unwrap();
152
153     let expected_user = User_ {
154       id: inserted_user.id,
155       name: "thommy".into(),
156       fedi_name: "rrf".into(),
157       preferred_username: None,
158       password_encrypted: "nope".into(),
159       email: None,
160       icon: None,
161       admin: false,
162       banned: false,
163       published: inserted_user.published,
164       updated: None,
165       show_nsfw: false,
166       theme: "darkly".into(),
167     };
168
169     let read_user = User_::read(&conn, inserted_user.id).unwrap();
170     let updated_user = User_::update(&conn, inserted_user.id, &new_user).unwrap();
171     let num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
172
173     assert_eq!(expected_user, read_user);
174     assert_eq!(expected_user, inserted_user);
175     assert_eq!(expected_user, updated_user);
176     assert_eq!(1, num_deleted);
177   }
178 }