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