2 use crate::schema::user_;
3 use crate::schema::user_::dsl::*;
4 use crate::{is_email_regex, naive_now, Settings};
5 use bcrypt::{hash, DEFAULT_COST};
6 use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
8 #[derive(Queryable, Identifiable, PartialEq, Debug)]
9 #[table_name = "user_"]
13 pub preferred_username: Option<String>,
14 pub password_encrypted: String,
15 pub email: Option<String>,
16 pub avatar: Option<String>,
19 pub published: chrono::NaiveDateTime,
20 pub updated: Option<chrono::NaiveDateTime>,
23 pub default_sort_type: i16,
24 pub default_listing_type: i16,
26 pub show_avatars: bool,
27 pub send_notifications_to_email: bool,
28 pub matrix_user_id: Option<String>,
30 pub bio: Option<String>,
32 pub private_key: Option<String>,
33 pub public_key: Option<String>,
34 pub last_refreshed_at: chrono::NaiveDateTime,
37 #[derive(Insertable, AsChangeset, Clone, Debug)]
38 #[table_name = "user_"]
41 pub preferred_username: Option<String>,
42 pub password_encrypted: String,
45 pub email: Option<String>,
46 pub avatar: Option<String>,
47 pub updated: Option<chrono::NaiveDateTime>,
50 pub default_sort_type: i16,
51 pub default_listing_type: i16,
53 pub show_avatars: bool,
54 pub send_notifications_to_email: bool,
55 pub matrix_user_id: Option<String>,
57 pub bio: Option<String>,
59 pub private_key: Option<String>,
60 pub public_key: Option<String>,
61 pub last_refreshed_at: Option<chrono::NaiveDateTime>,
64 impl Crud<UserForm> for User_ {
65 fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
66 user_.find(user_id).first::<Self>(conn)
68 fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> {
69 diesel::delete(user_.find(user_id)).execute(conn)
71 fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
72 insert_into(user_).values(form).get_result::<Self>(conn)
74 fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> {
75 diesel::update(user_.find(user_id))
77 .get_result::<Self>(conn)
82 pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
83 let mut edited_user = form.clone();
85 hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
86 edited_user.password_encrypted = password_hash;
88 Self::create(&conn, &edited_user)
91 // TODO do more individual updates like these
92 pub fn update_password(
96 ) -> Result<Self, Error> {
97 let password_hash = hash(new_password, DEFAULT_COST).expect("Couldn't hash password");
99 diesel::update(user_.find(user_id))
101 password_encrypted.eq(password_hash),
102 updated.eq(naive_now()),
104 .get_result::<Self>(conn)
107 pub fn read_from_name(conn: &PgConnection, from_user_name: String) -> Result<Self, Error> {
108 user_.filter(name.eq(from_user_name)).first::<Self>(conn)
111 pub fn add_admin(conn: &PgConnection, user_id: i32, added: bool) -> Result<Self, Error> {
112 diesel::update(user_.find(user_id))
113 .set(admin.eq(added))
114 .get_result::<Self>(conn)
117 pub fn ban_user(conn: &PgConnection, user_id: i32, ban: bool) -> Result<Self, Error> {
118 diesel::update(user_.find(user_id))
120 .get_result::<Self>(conn)
123 pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
124 use crate::schema::user_::dsl::*;
125 user_.filter(actor_id.eq(object_id)).first::<Self>(conn)
129 #[derive(Debug, Serialize, Deserialize)]
132 pub username: String,
136 pub default_sort_type: i16,
137 pub default_listing_type: i16,
139 pub avatar: Option<String>,
140 pub show_avatars: bool,
144 pub fn decode(jwt: &str) -> Result<TokenData<Claims>, jsonwebtoken::errors::Error> {
147 ..Validation::default()
151 &DecodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
159 pub fn jwt(&self) -> Jwt {
160 let my_claims = Claims {
162 username: self.name.to_owned(),
163 iss: Settings::get().hostname.to_owned(),
164 show_nsfw: self.show_nsfw,
165 theme: self.theme.to_owned(),
166 default_sort_type: self.default_sort_type,
167 default_listing_type: self.default_listing_type,
168 lang: self.lang.to_owned(),
169 avatar: self.avatar.to_owned(),
170 show_avatars: self.show_avatars.to_owned(),
175 &EncodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
180 pub fn find_by_username(conn: &PgConnection, username: &str) -> Result<Self, Error> {
181 user_.filter(name.eq(username)).first::<User_>(conn)
184 pub fn find_by_email(conn: &PgConnection, from_email: &str) -> Result<Self, Error> {
185 user_.filter(email.eq(from_email)).first::<User_>(conn)
188 pub fn find_by_email_or_username(
190 username_or_email: &str,
191 ) -> Result<Self, Error> {
192 if is_email_regex(username_or_email) {
193 User_::find_by_email(conn, username_or_email)
195 User_::find_by_username(conn, username_or_email)
199 pub fn get_profile_url(&self) -> String {
200 format!("https://{}/u/{}", Settings::get().hostname, self.name)
203 pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> {
204 let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims;
205 Self::read(&conn, claims.id)
216 let conn = establish_unpooled_connection();
218 let new_user = UserForm {
219 name: "thommy".into(),
220 preferred_username: None,
221 password_encrypted: "nope".into(),
223 matrix_user_id: None,
229 theme: "darkly".into(),
230 default_sort_type: SortType::Hot as i16,
231 default_listing_type: ListingType::Subscribed as i16,
232 lang: "browser".into(),
234 send_notifications_to_email: false,
235 actor_id: "changeme".into(),
240 last_refreshed_at: None,
243 let inserted_user = User_::create(&conn, &new_user).unwrap();
245 let expected_user = User_ {
246 id: inserted_user.id,
247 name: "thommy".into(),
248 preferred_username: None,
249 password_encrypted: "nope".into(),
251 matrix_user_id: None,
255 published: inserted_user.published,
258 theme: "darkly".into(),
259 default_sort_type: SortType::Hot as i16,
260 default_listing_type: ListingType::Subscribed as i16,
261 lang: "browser".into(),
263 send_notifications_to_email: false,
264 actor_id: "changeme".into(),
269 last_refreshed_at: inserted_user.published,
272 let read_user = User_::read(&conn, inserted_user.id).unwrap();
273 let updated_user = User_::update(&conn, inserted_user.id, &new_user).unwrap();
274 let num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
276 assert_eq!(expected_user, read_user);
277 assert_eq!(expected_user, inserted_user);
278 assert_eq!(expected_user, updated_user);
279 assert_eq!(1, num_deleted);