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