]> Untitled Git - lemmy.git/blob - server/src/db/user.rs
Adding emoji support
[lemmy.git] / server / src / db / user.rs
1 use schema::user_;
2 use schema::user_::dsl::*;
3 use super::*;
4 use {Settings, is_email_regex};
5 use jsonwebtoken::{encode, decode, Header, Validation, TokenData};
6 use bcrypt::{DEFAULT_COST, hash};
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 }
23
24 #[derive(Insertable, AsChangeset, Clone)]
25 #[table_name="user_"]
26 pub struct UserForm {
27     pub name: String,
28     pub fedi_name: String,
29     pub preferred_username: Option<String>,
30     pub password_encrypted: String,
31     pub admin: bool,
32     pub banned: bool,
33     pub email: Option<String>,
34     pub updated: Option<chrono::NaiveDateTime>
35 }
36
37 impl Crud<UserForm> for User_ {
38   fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
39     use schema::user_::dsl::*;
40     user_.find(user_id)
41       .first::<Self>(conn)
42   }
43   fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> {
44     diesel::delete(user_.find(user_id))
45       .execute(conn)
46   }
47   fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
48     insert_into(user_)
49       .values(form)
50       .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 = hash(&form.password_encrypted, DEFAULT_COST)
63       .expect("Couldn't hash password");
64     edited_user.password_encrypted = password_hash;
65
66     Self::create(&conn, &edited_user)
67
68   }
69   pub fn read_from_name(conn: &PgConnection, from_user_name: String) -> Result<Self, Error> {
70     user_.filter(name.eq(from_user_name))
71       .first::<Self>(conn)
72   }
73 }
74
75 #[derive(Debug, Serialize, Deserialize)]
76 pub struct Claims {
77   pub id: i32,
78   pub username: String,
79   pub iss: 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     };
100     encode(&Header::default(), &my_claims, Settings::get().jwt_secret.as_ref()).unwrap()
101   }
102
103   pub fn find_by_email_or_username(conn: &PgConnection, username_or_email: &str) -> Result<Self, Error> {
104     if is_email_regex(username_or_email) {
105       user_.filter(email.eq(username_or_email))
106         .first::<User_>(conn)
107     } else {
108       user_.filter(name.eq(username_or_email))
109         .first::<User_>(conn)
110     }
111   }
112
113   pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> {
114     let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims;
115     Self::read(&conn, claims.id)
116   }
117
118 }
119
120
121 #[cfg(test)]
122 mod tests {
123   use super::*;
124  #[test]
125   fn test_crud() {
126     let conn = establish_connection();
127     
128     let new_user = UserForm {
129       name: "thommy".into(),
130       fedi_name: "rrf".into(),
131       preferred_username: None,
132       password_encrypted: "nope".into(),
133       email: None,
134       admin: false,
135       banned: false,
136       updated: None
137     };
138
139     let inserted_user = User_::create(&conn, &new_user).unwrap();
140
141     let expected_user = User_ {
142       id: inserted_user.id,
143       name: "thommy".into(),
144       fedi_name: "rrf".into(),
145       preferred_username: None,
146       password_encrypted: "nope".into(),
147       email: None,
148       icon: None,
149       admin: false,
150       banned: false,
151       published: inserted_user.published,
152       updated: None
153     };
154     
155     let read_user = User_::read(&conn, inserted_user.id).unwrap();
156     let updated_user = User_::update(&conn, inserted_user.id, &new_user).unwrap();
157     let num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
158
159     assert_eq!(expected_user, read_user);
160     assert_eq!(expected_user, inserted_user);
161     assert_eq!(expected_user, updated_user);
162     assert_eq!(1, num_deleted);
163   }
164 }