]> Untitled Git - lemmy.git/blob - server/src/api/user.rs
Merge remote-tracking branch 'upstream/master'
[lemmy.git] / server / src / api / user.rs
1 use super::*;
2 use crate::settings::Settings;
3 use crate::{generate_random_string, send_email};
4 use bcrypt::verify;
5 use diesel::PgConnection;
6 use std::str::FromStr;
7
8 #[derive(Serialize, Deserialize, Debug)]
9 pub struct Login {
10   username_or_email: String,
11   password: String,
12 }
13
14 #[derive(Serialize, Deserialize)]
15 pub struct Register {
16   username: String,
17   email: Option<String>,
18   password: String,
19   password_verify: String,
20   admin: bool,
21   show_nsfw: bool,
22 }
23
24 #[derive(Serialize, Deserialize)]
25 pub struct SaveUserSettings {
26   show_nsfw: bool,
27   theme: String,
28   default_sort_type: i16,
29   default_listing_type: i16,
30   lang: String,
31   avatar: Option<String>,
32   email: Option<String>,
33   matrix_user_id: Option<String>,
34   new_password: Option<String>,
35   new_password_verify: Option<String>,
36   old_password: Option<String>,
37   show_avatars: bool,
38   send_notifications_to_email: bool,
39   auth: String,
40 }
41
42 #[derive(Serialize, Deserialize)]
43 pub struct LoginResponse {
44   jwt: String,
45 }
46
47 #[derive(Serialize, Deserialize)]
48 pub struct GetUserDetails {
49   user_id: Option<i32>,
50   username: Option<String>,
51   sort: String,
52   page: Option<i64>,
53   limit: Option<i64>,
54   community_id: Option<i32>,
55   saved_only: bool,
56   auth: Option<String>,
57 }
58
59 #[derive(Serialize, Deserialize)]
60 pub struct GetUserDetailsResponse {
61   user: UserView,
62   follows: Vec<CommunityFollowerView>,
63   moderates: Vec<CommunityModeratorView>,
64   comments: Vec<CommentView>,
65   posts: Vec<PostView>,
66   admins: Vec<UserView>,
67 }
68
69 #[derive(Serialize, Deserialize)]
70 pub struct GetRepliesResponse {
71   replies: Vec<ReplyView>,
72 }
73
74 #[derive(Serialize, Deserialize)]
75 pub struct GetUserMentionsResponse {
76   mentions: Vec<UserMentionView>,
77 }
78
79 #[derive(Serialize, Deserialize)]
80 pub struct MarkAllAsRead {
81   auth: String,
82 }
83
84 #[derive(Serialize, Deserialize)]
85 pub struct AddAdmin {
86   user_id: i32,
87   added: bool,
88   auth: String,
89 }
90
91 #[derive(Serialize, Deserialize)]
92 pub struct AddAdminResponse {
93   admins: Vec<UserView>,
94 }
95
96 #[derive(Serialize, Deserialize)]
97 pub struct BanUser {
98   user_id: i32,
99   ban: bool,
100   reason: Option<String>,
101   expires: Option<i64>,
102   auth: String,
103 }
104
105 #[derive(Serialize, Deserialize)]
106 pub struct BanUserResponse {
107   user: UserView,
108   banned: bool,
109 }
110
111 #[derive(Serialize, Deserialize)]
112 pub struct GetReplies {
113   sort: String,
114   page: Option<i64>,
115   limit: Option<i64>,
116   unread_only: bool,
117   auth: String,
118 }
119
120 #[derive(Serialize, Deserialize)]
121 pub struct GetUserMentions {
122   sort: String,
123   page: Option<i64>,
124   limit: Option<i64>,
125   unread_only: bool,
126   auth: String,
127 }
128
129 #[derive(Serialize, Deserialize)]
130 pub struct EditUserMention {
131   user_mention_id: i32,
132   read: Option<bool>,
133   auth: String,
134 }
135
136 #[derive(Serialize, Deserialize, Clone)]
137 pub struct UserMentionResponse {
138   mention: UserMentionView,
139 }
140
141 #[derive(Serialize, Deserialize)]
142 pub struct DeleteAccount {
143   password: String,
144   auth: String,
145 }
146
147 #[derive(Serialize, Deserialize)]
148 pub struct PasswordReset {
149   email: String,
150 }
151
152 #[derive(Serialize, Deserialize, Clone)]
153 pub struct PasswordResetResponse {}
154
155 #[derive(Serialize, Deserialize)]
156 pub struct PasswordChange {
157   token: String,
158   password: String,
159   password_verify: String,
160 }
161
162 #[derive(Serialize, Deserialize)]
163 pub struct CreatePrivateMessage {
164   content: String,
165   pub recipient_id: i32,
166   auth: String,
167 }
168
169 #[derive(Serialize, Deserialize)]
170 pub struct EditPrivateMessage {
171   edit_id: i32,
172   content: Option<String>,
173   deleted: Option<bool>,
174   read: Option<bool>,
175   auth: String,
176 }
177
178 #[derive(Serialize, Deserialize)]
179 pub struct GetPrivateMessages {
180   unread_only: bool,
181   page: Option<i64>,
182   limit: Option<i64>,
183   auth: String,
184 }
185
186 #[derive(Serialize, Deserialize, Clone)]
187 pub struct PrivateMessagesResponse {
188   messages: Vec<PrivateMessageView>,
189 }
190
191 #[derive(Serialize, Deserialize, Clone)]
192 pub struct PrivateMessageResponse {
193   message: PrivateMessageView,
194 }
195
196 #[derive(Serialize, Deserialize, Debug)]
197 pub struct UserJoin {
198   auth: String,
199 }
200
201 #[derive(Serialize, Deserialize, Clone)]
202 pub struct UserJoinResponse {
203   pub user_id: i32,
204 }
205
206 impl Perform<LoginResponse> for Oper<Login> {
207   fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> {
208     let data: &Login = &self.data;
209
210     // Fetch that username / email
211     let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) {
212       Ok(user) => user,
213       Err(_e) => return Err(APIError::err("couldnt_find_that_username_or_email").into()),
214     };
215
216     // Verify the password
217     let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
218     if !valid {
219       return Err(APIError::err("password_incorrect").into());
220     }
221
222     // Return the jwt
223     Ok(LoginResponse { jwt: user.jwt() })
224   }
225 }
226
227 impl Perform<LoginResponse> for Oper<Register> {
228   fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> {
229     let data: &Register = &self.data;
230
231     // Make sure site has open registration
232     if let Ok(site) = SiteView::read(&conn) {
233       if !site.open_registration {
234         return Err(APIError::err("registration_closed").into());
235       }
236     }
237
238     // Make sure passwords match
239     if data.password != data.password_verify {
240       return Err(APIError::err("passwords_dont_match").into());
241     }
242
243     if let Err(slurs) = slur_check(&data.username) {
244       return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
245     }
246
247     // Make sure there are no admins
248     if data.admin && !UserView::admins(&conn)?.is_empty() {
249       return Err(APIError::err("admin_already_created").into());
250     }
251
252     // Register the new user
253     let user_form = UserForm {
254       name: data.username.to_owned(),
255       fedi_name: Settings::get().hostname.to_owned(),
256       email: data.email.to_owned(),
257       matrix_user_id: None,
258       avatar: None,
259       password_encrypted: data.password.to_owned(),
260       preferred_username: None,
261       updated: None,
262       admin: data.admin,
263       banned: false,
264       show_nsfw: data.show_nsfw,
265       theme: "darkly".into(),
266       default_sort_type: SortType::Hot as i16,
267       default_listing_type: ListingType::Subscribed as i16,
268       lang: "browser".into(),
269       show_avatars: true,
270       send_notifications_to_email: false,
271     };
272
273     // Create the user
274     let inserted_user = match User_::register(&conn, &user_form) {
275       Ok(user) => user,
276       Err(e) => {
277         let err_type = if e.to_string()
278           == "duplicate key value violates unique constraint \"user__email_key\""
279         {
280           "email_already_exists"
281         } else {
282           "user_already_exists"
283         };
284
285         return Err(APIError::err(err_type).into());
286       }
287     };
288
289     // Create the main community if it doesn't exist
290     let main_community: Community = match Community::read(&conn, 2) {
291       Ok(c) => c,
292       Err(_e) => {
293         let community_form = CommunityForm {
294           name: "main".to_string(),
295           title: "The Default Community".to_string(),
296           description: Some("The Default Community".to_string()),
297           category_id: 1,
298           nsfw: false,
299           creator_id: inserted_user.id,
300           removed: None,
301           deleted: None,
302           updated: None,
303         };
304         Community::create(&conn, &community_form).unwrap()
305       }
306     };
307
308     // Sign them up for main community no matter what
309     let community_follower_form = CommunityFollowerForm {
310       community_id: main_community.id,
311       user_id: inserted_user.id,
312     };
313
314     let _inserted_community_follower =
315       match CommunityFollower::follow(&conn, &community_follower_form) {
316         Ok(user) => user,
317         Err(_e) => return Err(APIError::err("community_follower_already_exists").into()),
318       };
319
320     // If its an admin, add them as a mod and follower to main
321     if data.admin {
322       let community_moderator_form = CommunityModeratorForm {
323         community_id: main_community.id,
324         user_id: inserted_user.id,
325       };
326
327       let _inserted_community_moderator =
328         match CommunityModerator::join(&conn, &community_moderator_form) {
329           Ok(user) => user,
330           Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()),
331         };
332     }
333
334     // Return the jwt
335     Ok(LoginResponse {
336       jwt: inserted_user.jwt(),
337     })
338   }
339 }
340
341 impl Perform<LoginResponse> for Oper<SaveUserSettings> {
342   fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> {
343     let data: &SaveUserSettings = &self.data;
344
345     let claims = match Claims::decode(&data.auth) {
346       Ok(claims) => claims.claims,
347       Err(_e) => return Err(APIError::err("not_logged_in").into()),
348     };
349
350     let user_id = claims.id;
351
352     let read_user = User_::read(&conn, user_id)?;
353
354     let email = match &data.email {
355       Some(email) => Some(email.to_owned()),
356       None => read_user.email,
357     };
358
359     let password_encrypted = match &data.new_password {
360       Some(new_password) => {
361         match &data.new_password_verify {
362           Some(new_password_verify) => {
363             // Make sure passwords match
364             if new_password != new_password_verify {
365               return Err(APIError::err("passwords_dont_match").into());
366             }
367
368             // Check the old password
369             match &data.old_password {
370               Some(old_password) => {
371                 let valid: bool =
372                   verify(old_password, &read_user.password_encrypted).unwrap_or(false);
373                 if !valid {
374                   return Err(APIError::err("password_incorrect").into());
375                 }
376                 User_::update_password(&conn, user_id, &new_password)?.password_encrypted
377               }
378               None => return Err(APIError::err("password_incorrect").into()),
379             }
380           }
381           None => return Err(APIError::err("passwords_dont_match").into()),
382         }
383       }
384       None => read_user.password_encrypted,
385     };
386
387     let user_form = UserForm {
388       name: read_user.name,
389       fedi_name: read_user.fedi_name,
390       email,
391       matrix_user_id: data.matrix_user_id.to_owned(),
392       avatar: data.avatar.to_owned(),
393       password_encrypted,
394       preferred_username: read_user.preferred_username,
395       updated: Some(naive_now()),
396       admin: read_user.admin,
397       banned: read_user.banned,
398       show_nsfw: data.show_nsfw,
399       theme: data.theme.to_owned(),
400       default_sort_type: data.default_sort_type,
401       default_listing_type: data.default_listing_type,
402       lang: data.lang.to_owned(),
403       show_avatars: data.show_avatars,
404       send_notifications_to_email: data.send_notifications_to_email,
405     };
406
407     let updated_user = match User_::update(&conn, user_id, &user_form) {
408       Ok(user) => user,
409       Err(e) => {
410         let err_type = if e.to_string()
411           == "duplicate key value violates unique constraint \"user__email_key\""
412         {
413           "email_already_exists"
414         } else {
415           "user_already_exists"
416         };
417
418         return Err(APIError::err(err_type).into());
419       }
420     };
421
422     // Return the jwt
423     Ok(LoginResponse {
424       jwt: updated_user.jwt(),
425     })
426   }
427 }
428
429 impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
430   fn perform(&self, conn: &PgConnection) -> Result<GetUserDetailsResponse, Error> {
431     let data: &GetUserDetails = &self.data;
432
433     let user_claims: Option<Claims> = match &data.auth {
434       Some(auth) => match Claims::decode(&auth) {
435         Ok(claims) => Some(claims.claims),
436         Err(_e) => None,
437       },
438       None => None,
439     };
440
441     let user_id = match &user_claims {
442       Some(claims) => Some(claims.id),
443       None => None,
444     };
445
446     let show_nsfw = match &user_claims {
447       Some(claims) => claims.show_nsfw,
448       None => false,
449     };
450
451     let sort = SortType::from_str(&data.sort)?;
452
453     let user_details_id = match data.user_id {
454       Some(id) => id,
455       None => {
456         match User_::read_from_name(
457           &conn,
458           data
459             .username
460             .to_owned()
461             .unwrap_or_else(|| "admin".to_string()),
462         ) {
463           Ok(user) => user.id,
464           Err(_e) => return Err(APIError::err("couldnt_find_that_username_or_email").into()),
465         }
466       }
467     };
468
469     let user_view = UserView::read(&conn, user_details_id)?;
470
471     let mut posts_query = PostQueryBuilder::create(&conn)
472       .sort(&sort)
473       .show_nsfw(show_nsfw)
474       .saved_only(data.saved_only)
475       .for_community_id(data.community_id)
476       .my_user_id(user_id)
477       .page(data.page)
478       .limit(data.limit);
479
480     let mut comments_query = CommentQueryBuilder::create(&conn)
481       .sort(&sort)
482       .saved_only(data.saved_only)
483       .my_user_id(user_id)
484       .page(data.page)
485       .limit(data.limit);
486
487     // If its saved only, you don't care what creator it was
488     // Or, if its not saved, then you only want it for that specific creator
489     if !data.saved_only {
490       posts_query = posts_query.for_creator_id(user_details_id);
491       comments_query = comments_query.for_creator_id(user_details_id);
492     }
493
494     let posts = posts_query.list()?;
495     let comments = comments_query.list()?;
496
497     let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
498     let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
499     let site_creator_id = Site::read(&conn, 1)?.creator_id;
500     let mut admins = UserView::admins(&conn)?;
501     let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
502     let creator_user = admins.remove(creator_index);
503     admins.insert(0, creator_user);
504
505     // Return the jwt
506     Ok(GetUserDetailsResponse {
507       user: user_view,
508       follows,
509       moderates,
510       comments,
511       posts,
512       admins,
513     })
514   }
515 }
516
517 impl Perform<AddAdminResponse> for Oper<AddAdmin> {
518   fn perform(&self, conn: &PgConnection) -> Result<AddAdminResponse, Error> {
519     let data: &AddAdmin = &self.data;
520
521     let claims = match Claims::decode(&data.auth) {
522       Ok(claims) => claims.claims,
523       Err(_e) => return Err(APIError::err("not_logged_in").into()),
524     };
525
526     let user_id = claims.id;
527
528     // Make sure user is an admin
529     if !UserView::read(&conn, user_id)?.admin {
530       return Err(APIError::err("not_an_admin").into());
531     }
532
533     let read_user = User_::read(&conn, data.user_id)?;
534
535     // TODO make addadmin easier
536     let user_form = UserForm {
537       name: read_user.name,
538       fedi_name: read_user.fedi_name,
539       email: read_user.email,
540       matrix_user_id: read_user.matrix_user_id,
541       avatar: read_user.avatar,
542       password_encrypted: read_user.password_encrypted,
543       preferred_username: read_user.preferred_username,
544       updated: Some(naive_now()),
545       admin: data.added,
546       banned: read_user.banned,
547       show_nsfw: read_user.show_nsfw,
548       theme: read_user.theme,
549       default_sort_type: read_user.default_sort_type,
550       default_listing_type: read_user.default_listing_type,
551       lang: read_user.lang,
552       show_avatars: read_user.show_avatars,
553       send_notifications_to_email: read_user.send_notifications_to_email,
554     };
555
556     match User_::update(&conn, data.user_id, &user_form) {
557       Ok(user) => user,
558       Err(_e) => return Err(APIError::err("couldnt_update_user").into()),
559     };
560
561     // Mod tables
562     let form = ModAddForm {
563       mod_user_id: user_id,
564       other_user_id: data.user_id,
565       removed: Some(!data.added),
566     };
567
568     ModAdd::create(&conn, &form)?;
569
570     let site_creator_id = Site::read(&conn, 1)?.creator_id;
571     let mut admins = UserView::admins(&conn)?;
572     let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
573     let creator_user = admins.remove(creator_index);
574     admins.insert(0, creator_user);
575
576     Ok(AddAdminResponse { admins })
577   }
578 }
579
580 impl Perform<BanUserResponse> for Oper<BanUser> {
581   fn perform(&self, conn: &PgConnection) -> Result<BanUserResponse, Error> {
582     let data: &BanUser = &self.data;
583
584     let claims = match Claims::decode(&data.auth) {
585       Ok(claims) => claims.claims,
586       Err(_e) => return Err(APIError::err("not_logged_in").into()),
587     };
588
589     let user_id = claims.id;
590
591     // Make sure user is an admin
592     if !UserView::read(&conn, user_id)?.admin {
593       return Err(APIError::err("not_an_admin").into());
594     }
595
596     let read_user = User_::read(&conn, data.user_id)?;
597
598     // TODO make bans and addadmins easier
599     let user_form = UserForm {
600       name: read_user.name,
601       fedi_name: read_user.fedi_name,
602       email: read_user.email,
603       matrix_user_id: read_user.matrix_user_id,
604       avatar: read_user.avatar,
605       password_encrypted: read_user.password_encrypted,
606       preferred_username: read_user.preferred_username,
607       updated: Some(naive_now()),
608       admin: read_user.admin,
609       banned: data.ban,
610       show_nsfw: read_user.show_nsfw,
611       theme: read_user.theme,
612       default_sort_type: read_user.default_sort_type,
613       default_listing_type: read_user.default_listing_type,
614       lang: read_user.lang,
615       show_avatars: read_user.show_avatars,
616       send_notifications_to_email: read_user.send_notifications_to_email,
617     };
618
619     match User_::update(&conn, data.user_id, &user_form) {
620       Ok(user) => user,
621       Err(_e) => return Err(APIError::err("couldnt_update_user").into()),
622     };
623
624     // Mod tables
625     let expires = match data.expires {
626       Some(time) => Some(naive_from_unix(time)),
627       None => None,
628     };
629
630     let form = ModBanForm {
631       mod_user_id: user_id,
632       other_user_id: data.user_id,
633       reason: data.reason.to_owned(),
634       banned: Some(data.ban),
635       expires,
636     };
637
638     ModBan::create(&conn, &form)?;
639
640     let user_view = UserView::read(&conn, data.user_id)?;
641
642     Ok(BanUserResponse {
643       user: user_view,
644       banned: data.ban,
645     })
646   }
647 }
648
649 impl Perform<GetRepliesResponse> for Oper<GetReplies> {
650   fn perform(&self, conn: &PgConnection) -> Result<GetRepliesResponse, Error> {
651     let data: &GetReplies = &self.data;
652
653     let claims = match Claims::decode(&data.auth) {
654       Ok(claims) => claims.claims,
655       Err(_e) => return Err(APIError::err("not_logged_in").into()),
656     };
657
658     let user_id = claims.id;
659
660     let sort = SortType::from_str(&data.sort)?;
661
662     let replies = ReplyQueryBuilder::create(&conn, user_id)
663       .sort(&sort)
664       .unread_only(data.unread_only)
665       .page(data.page)
666       .limit(data.limit)
667       .list()?;
668
669     Ok(GetRepliesResponse { replies })
670   }
671 }
672
673 impl Perform<GetUserMentionsResponse> for Oper<GetUserMentions> {
674   fn perform(&self, conn: &PgConnection) -> Result<GetUserMentionsResponse, Error> {
675     let data: &GetUserMentions = &self.data;
676
677     let claims = match Claims::decode(&data.auth) {
678       Ok(claims) => claims.claims,
679       Err(_e) => return Err(APIError::err("not_logged_in").into()),
680     };
681
682     let user_id = claims.id;
683
684     let sort = SortType::from_str(&data.sort)?;
685
686     let mentions = UserMentionQueryBuilder::create(&conn, user_id)
687       .sort(&sort)
688       .unread_only(data.unread_only)
689       .page(data.page)
690       .limit(data.limit)
691       .list()?;
692
693     Ok(GetUserMentionsResponse { mentions })
694   }
695 }
696
697 impl Perform<UserMentionResponse> for Oper<EditUserMention> {
698   fn perform(&self, conn: &PgConnection) -> Result<UserMentionResponse, Error> {
699     let data: &EditUserMention = &self.data;
700
701     let claims = match Claims::decode(&data.auth) {
702       Ok(claims) => claims.claims,
703       Err(_e) => return Err(APIError::err("not_logged_in").into()),
704     };
705
706     let user_id = claims.id;
707
708     let user_mention = UserMention::read(&conn, data.user_mention_id)?;
709
710     let user_mention_form = UserMentionForm {
711       recipient_id: user_id,
712       comment_id: user_mention.comment_id,
713       read: data.read.to_owned(),
714     };
715
716     let _updated_user_mention =
717       match UserMention::update(&conn, user_mention.id, &user_mention_form) {
718         Ok(comment) => comment,
719         Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
720       };
721
722     let user_mention_view = UserMentionView::read(&conn, user_mention.id, user_id)?;
723
724     Ok(UserMentionResponse {
725       mention: user_mention_view,
726     })
727   }
728 }
729
730 impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
731   fn perform(&self, conn: &PgConnection) -> Result<GetRepliesResponse, Error> {
732     let data: &MarkAllAsRead = &self.data;
733
734     let claims = match Claims::decode(&data.auth) {
735       Ok(claims) => claims.claims,
736       Err(_e) => return Err(APIError::err("not_logged_in").into()),
737     };
738
739     let user_id = claims.id;
740
741     let replies = ReplyQueryBuilder::create(&conn, user_id)
742       .unread_only(true)
743       .page(1)
744       .limit(999)
745       .list()?;
746
747     for reply in &replies {
748       let comment_form = CommentForm {
749         content: reply.to_owned().content,
750         parent_id: reply.to_owned().parent_id,
751         post_id: reply.to_owned().post_id,
752         creator_id: reply.to_owned().creator_id,
753         removed: None,
754         deleted: None,
755         read: Some(true),
756         updated: reply.to_owned().updated,
757       };
758
759       let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
760         Ok(comment) => comment,
761         Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
762       };
763     }
764
765     // Mentions
766     let mentions = UserMentionQueryBuilder::create(&conn, user_id)
767       .unread_only(true)
768       .page(1)
769       .limit(999)
770       .list()?;
771
772     for mention in &mentions {
773       let mention_form = UserMentionForm {
774         recipient_id: mention.to_owned().recipient_id,
775         comment_id: mention.to_owned().id,
776         read: Some(true),
777       };
778
779       let _updated_mention =
780         match UserMention::update(&conn, mention.user_mention_id, &mention_form) {
781           Ok(mention) => mention,
782           Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
783         };
784     }
785
786     // messages
787     let messages = PrivateMessageQueryBuilder::create(&conn, user_id)
788       .page(1)
789       .limit(999)
790       .unread_only(true)
791       .list()?;
792
793     for message in &messages {
794       let private_message_form = PrivateMessageForm {
795         content: None,
796         creator_id: message.to_owned().creator_id,
797         recipient_id: message.to_owned().recipient_id,
798         deleted: None,
799         read: Some(true),
800         updated: None,
801       };
802
803       let _updated_message = match PrivateMessage::update(&conn, message.id, &private_message_form)
804       {
805         Ok(message) => message,
806         Err(_e) => return Err(APIError::err("couldnt_update_private_message").into()),
807       };
808     }
809
810     Ok(GetRepliesResponse { replies: vec![] })
811   }
812 }
813
814 impl Perform<LoginResponse> for Oper<DeleteAccount> {
815   fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> {
816     let data: &DeleteAccount = &self.data;
817
818     let claims = match Claims::decode(&data.auth) {
819       Ok(claims) => claims.claims,
820       Err(_e) => return Err(APIError::err("not_logged_in").into()),
821     };
822
823     let user_id = claims.id;
824
825     let user: User_ = User_::read(&conn, user_id)?;
826
827     // Verify the password
828     let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
829     if !valid {
830       return Err(APIError::err("password_incorrect").into());
831     }
832
833     // Comments
834     let comments = CommentQueryBuilder::create(&conn)
835       .for_creator_id(user_id)
836       .limit(std::i64::MAX)
837       .list()?;
838
839     for comment in &comments {
840       let comment_form = CommentForm {
841         content: "*Permananently Deleted*".to_string(),
842         parent_id: comment.to_owned().parent_id,
843         post_id: comment.to_owned().post_id,
844         creator_id: comment.to_owned().creator_id,
845         removed: None,
846         deleted: Some(true),
847         read: None,
848         updated: Some(naive_now()),
849       };
850
851       let _updated_comment = match Comment::update(&conn, comment.id, &comment_form) {
852         Ok(comment) => comment,
853         Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
854       };
855     }
856
857     // Posts
858     let posts = PostQueryBuilder::create(&conn)
859       .sort(&SortType::New)
860       .for_creator_id(user_id)
861       .limit(std::i64::MAX)
862       .list()?;
863
864     for post in &posts {
865       let post_form = PostForm {
866         name: "*Permananently Deleted*".to_string(),
867         url: Some("https://deleted.com".to_string()),
868         body: Some("*Permananently Deleted*".to_string()),
869         creator_id: post.to_owned().creator_id,
870         community_id: post.to_owned().community_id,
871         removed: None,
872         deleted: Some(true),
873         nsfw: post.to_owned().nsfw,
874         locked: None,
875         stickied: None,
876         updated: Some(naive_now()),
877       };
878
879       let _updated_post = match Post::update(&conn, post.id, &post_form) {
880         Ok(post) => post,
881         Err(_e) => return Err(APIError::err("couldnt_update_post").into()),
882       };
883     }
884
885     Ok(LoginResponse {
886       jwt: data.auth.to_owned(),
887     })
888   }
889 }
890
891 impl Perform<PasswordResetResponse> for Oper<PasswordReset> {
892   fn perform(&self, conn: &PgConnection) -> Result<PasswordResetResponse, Error> {
893     let data: &PasswordReset = &self.data;
894
895     // Fetch that email
896     let user: User_ = match User_::find_by_email(&conn, &data.email) {
897       Ok(user) => user,
898       Err(_e) => return Err(APIError::err("couldnt_find_that_username_or_email").into()),
899     };
900
901     // Generate a random token
902     let token = generate_random_string();
903
904     // Insert the row
905     PasswordResetRequest::create_token(&conn, user.id, &token)?;
906
907     // Email the pure token to the user.
908     // TODO no i18n support here.
909     let user_email = &user.email.expect("email");
910     let subject = &format!("Password reset for {}", user.name);
911     let hostname = &format!("https://{}", Settings::get().hostname); //TODO add https for now.
912     let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", user.name, hostname, &token);
913     match send_email(subject, user_email, &user.name, html) {
914       Ok(_o) => _o,
915       Err(_e) => return Err(APIError::err(&_e).into()),
916     };
917
918     Ok(PasswordResetResponse {})
919   }
920 }
921
922 impl Perform<LoginResponse> for Oper<PasswordChange> {
923   fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> {
924     let data: &PasswordChange = &self.data;
925
926     // Fetch the user_id from the token
927     let user_id = PasswordResetRequest::read_from_token(&conn, &data.token)?.user_id;
928
929     // Make sure passwords match
930     if data.password != data.password_verify {
931       return Err(APIError::err("passwords_dont_match").into());
932     }
933
934     // Update the user with the new password
935     let updated_user = match User_::update_password(&conn, user_id, &data.password) {
936       Ok(user) => user,
937       Err(_e) => return Err(APIError::err("couldnt_update_user").into()),
938     };
939
940     // Return the jwt
941     Ok(LoginResponse {
942       jwt: updated_user.jwt(),
943     })
944   }
945 }
946
947 impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> {
948   fn perform(&self, conn: &PgConnection) -> Result<PrivateMessageResponse, Error> {
949     let data: &CreatePrivateMessage = &self.data;
950
951     let claims = match Claims::decode(&data.auth) {
952       Ok(claims) => claims.claims,
953       Err(_e) => return Err(APIError::err("not_logged_in").into()),
954     };
955
956     let user_id = claims.id;
957
958     let hostname = &format!("https://{}", Settings::get().hostname);
959
960     // Check for a site ban
961     if UserView::read(&conn, user_id)?.banned {
962       return Err(APIError::err("site_ban").into());
963     }
964
965     let content_slurs_removed = remove_slurs(&data.content.to_owned());
966
967     let private_message_form = PrivateMessageForm {
968       content: Some(content_slurs_removed.to_owned()),
969       creator_id: user_id,
970       recipient_id: data.recipient_id,
971       deleted: None,
972       read: None,
973       updated: None,
974     };
975
976     let inserted_private_message = match PrivateMessage::create(&conn, &private_message_form) {
977       Ok(private_message) => private_message,
978       Err(_e) => {
979         return Err(APIError::err("couldnt_create_private_message").into());
980       }
981     };
982
983     // Send notifications to the recipient
984     let recipient_user = User_::read(&conn, data.recipient_id)?;
985     if recipient_user.send_notifications_to_email {
986       if let Some(email) = recipient_user.email {
987         let subject = &format!(
988           "{} - Private Message from {}",
989           Settings::get().hostname,
990           claims.username
991         );
992         let html = &format!(
993           "<h1>Private Message</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
994           claims.username, &content_slurs_removed, hostname
995         );
996         match send_email(subject, &email, &recipient_user.name, html) {
997           Ok(_o) => _o,
998           Err(e) => eprintln!("{}", e),
999         };
1000       }
1001     }
1002
1003     let message = PrivateMessageView::read(&conn, inserted_private_message.id)?;
1004
1005     Ok(PrivateMessageResponse { message })
1006   }
1007 }
1008
1009 impl Perform<PrivateMessageResponse> for Oper<EditPrivateMessage> {
1010   fn perform(&self, conn: &PgConnection) -> Result<PrivateMessageResponse, Error> {
1011     let data: &EditPrivateMessage = &self.data;
1012
1013     let claims = match Claims::decode(&data.auth) {
1014       Ok(claims) => claims.claims,
1015       Err(_e) => return Err(APIError::err("not_logged_in").into()),
1016     };
1017
1018     let user_id = claims.id;
1019
1020     let orig_private_message = PrivateMessage::read(&conn, data.edit_id)?;
1021
1022     // Check for a site ban
1023     if UserView::read(&conn, user_id)?.banned {
1024       return Err(APIError::err("site_ban").into());
1025     }
1026
1027     // Check to make sure they are the creator (or the recipient marking as read
1028     if !(data.read.is_some() && orig_private_message.recipient_id.eq(&user_id)
1029       || orig_private_message.creator_id.eq(&user_id))
1030     {
1031       return Err(APIError::err("no_private_message_edit_allowed").into());
1032     }
1033
1034     let content_slurs_removed = match &data.content {
1035       Some(content) => Some(remove_slurs(content)),
1036       None => None,
1037     };
1038
1039     let private_message_form = PrivateMessageForm {
1040       content: content_slurs_removed,
1041       creator_id: orig_private_message.creator_id,
1042       recipient_id: orig_private_message.recipient_id,
1043       deleted: data.deleted.to_owned(),
1044       read: data.read.to_owned(),
1045       updated: if data.read.is_some() {
1046         orig_private_message.updated
1047       } else {
1048         Some(naive_now())
1049       },
1050     };
1051
1052     let _updated_private_message =
1053       match PrivateMessage::update(&conn, data.edit_id, &private_message_form) {
1054         Ok(private_message) => private_message,
1055         Err(_e) => return Err(APIError::err("couldnt_update_private_message").into()),
1056       };
1057
1058     let message = PrivateMessageView::read(&conn, data.edit_id)?;
1059
1060     Ok(PrivateMessageResponse { message })
1061   }
1062 }
1063
1064 impl Perform<PrivateMessagesResponse> for Oper<GetPrivateMessages> {
1065   fn perform(&self, conn: &PgConnection) -> Result<PrivateMessagesResponse, Error> {
1066     let data: &GetPrivateMessages = &self.data;
1067
1068     let claims = match Claims::decode(&data.auth) {
1069       Ok(claims) => claims.claims,
1070       Err(_e) => return Err(APIError::err("not_logged_in").into()),
1071     };
1072
1073     let user_id = claims.id;
1074
1075     let messages = PrivateMessageQueryBuilder::create(&conn, user_id)
1076       .page(data.page)
1077       .limit(data.limit)
1078       .unread_only(data.unread_only)
1079       .list()?;
1080
1081     Ok(PrivateMessagesResponse { messages })
1082   }
1083 }
1084
1085 impl Perform<UserJoinResponse> for Oper<UserJoin> {
1086   fn perform(&self, _conn: &PgConnection) -> Result<UserJoinResponse, Error> {
1087     let data: &UserJoin = &self.data;
1088
1089     let claims = match Claims::decode(&data.auth) {
1090       Ok(claims) => claims.claims,
1091       Err(_e) => return Err(APIError::err("not_logged_in").into()),
1092     };
1093
1094     let user_id = claims.id;
1095     Ok(UserJoinResponse { user_id })
1096   }
1097 }