]> Untitled Git - lemmy.git/blob - server/src/api/user.rs
Adding emoji support.
[lemmy.git] / server / src / api / user.rs
1 use super::*;
2 use std::str::FromStr;
3 use bcrypt::{verify};
4
5 #[derive(Serialize, Deserialize, Debug)]
6 pub struct Login {
7   username_or_email: String,
8   password: String
9 }
10
11 #[derive(Serialize, Deserialize)]
12 pub struct Register {
13   username: String,
14   email: Option<String>,
15   password: String,
16   password_verify: String,
17   admin: bool,
18   show_nsfw: bool,
19 }
20
21 #[derive(Serialize, Deserialize)]
22 pub struct SaveUserSettings {
23   show_nsfw: bool,
24   auth: String,
25 }
26
27 #[derive(Serialize, Deserialize)]
28 pub struct LoginResponse {
29   op: String,
30   jwt: String
31 }
32
33 #[derive(Serialize, Deserialize)]
34 pub struct GetUserDetails {
35   user_id: Option<i32>,
36   username: Option<String>,
37   sort: String,
38   page: Option<i64>,
39   limit: Option<i64>,
40   community_id: Option<i32>,
41   saved_only: bool,
42   auth: Option<String>,
43 }
44
45 #[derive(Serialize, Deserialize)]
46 pub struct GetUserDetailsResponse {
47   op: String,
48   user: UserView,
49   follows: Vec<CommunityFollowerView>,
50   moderates: Vec<CommunityModeratorView>,
51   comments: Vec<CommentView>,
52   posts: Vec<PostView>,
53 }
54
55 #[derive(Serialize, Deserialize)]
56 pub struct GetRepliesResponse {
57   op: String,
58   replies: Vec<ReplyView>,
59 }
60
61 #[derive(Serialize, Deserialize)]
62 pub struct MarkAllAsRead {
63   auth: String
64 }
65
66 #[derive(Serialize, Deserialize)]
67 pub struct AddAdmin {
68   user_id: i32,
69   added: bool,
70   auth: String
71 }
72
73 #[derive(Serialize, Deserialize)]
74 pub struct AddAdminResponse {
75   op: String,
76   admins: Vec<UserView>,
77 }
78
79 #[derive(Serialize, Deserialize)]
80 pub struct BanUser {
81   user_id: i32,
82   ban: bool,
83   reason: Option<String>,
84   expires: Option<i64>,
85   auth: String
86 }
87
88 #[derive(Serialize, Deserialize)]
89 pub struct BanUserResponse {
90   op: String,
91   user: UserView,
92   banned: bool,
93 }
94
95 #[derive(Serialize, Deserialize)]
96 pub struct GetReplies {
97   sort: String,
98   page: Option<i64>,
99   limit: Option<i64>,
100   unread_only: bool,
101   auth: String
102 }
103
104 impl Perform<LoginResponse> for Oper<Login> {
105   fn perform(&self) -> Result<LoginResponse, Error> {
106     let data: &Login = &self.data;
107     let conn = establish_connection();
108
109     // Fetch that username / email
110     let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) {
111       Ok(user) => user,
112       Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email"))?
113     };
114
115     // Verify the password
116     let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
117     if !valid {
118       return Err(APIError::err(&self.op, "password_incorrect"))?
119     }
120
121     // Return the jwt
122     Ok(
123       LoginResponse {
124         op: self.op.to_string(),
125         jwt: user.jwt()
126       }
127       )
128   }
129 }
130
131
132 impl Perform<LoginResponse> for Oper<Register> {
133   fn perform(&self) -> Result<LoginResponse, Error> {
134     let data: &Register = &self.data;
135     let conn = establish_connection();
136
137     // Make sure passwords match
138     if &data.password != &data.password_verify {
139       return Err(APIError::err(&self.op, "passwords_dont_match"))?
140     }
141
142     if has_slurs(&data.username) {
143       return Err(APIError::err(&self.op, "no_slurs"))?
144     }
145
146     // Make sure there are no admins
147     if data.admin && UserView::admins(&conn)?.len() > 0 {
148       return Err(APIError::err(&self.op, "admin_already_created"))?
149     }
150
151     // Register the new user
152     let user_form = UserForm {
153       name: data.username.to_owned(),
154       fedi_name: Settings::get().hostname.into(),
155       email: data.email.to_owned(),
156       password_encrypted: data.password.to_owned(),
157       preferred_username: None,
158       updated: None,
159       admin: data.admin,
160       banned: false,
161       show_nsfw: data.show_nsfw,
162     };
163
164     // Create the user
165     let inserted_user = match User_::register(&conn, &user_form) {
166       Ok(user) => user,
167       Err(_e) => {
168         return Err(APIError::err(&self.op, "user_already_exists"))?
169       }
170     };
171
172     // Create the main community if it doesn't exist
173     let main_community: Community = match Community::read(&conn, 2) {
174       Ok(c) => c,
175       Err(_e) => {
176         let community_form = CommunityForm {
177           name: "main".to_string(),
178           title: "The Default Community".to_string(),
179           description: Some("The Default Community".to_string()),
180           category_id: 1,
181           nsfw: false,
182           creator_id: inserted_user.id,
183           removed: None,
184           deleted: None,
185           updated: None,
186         };
187         Community::create(&conn, &community_form).unwrap()
188       }
189     };
190
191     // Sign them up for main community no matter what
192     let community_follower_form = CommunityFollowerForm {
193       community_id: main_community.id,
194       user_id: inserted_user.id,
195     };
196
197     let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
198       Ok(user) => user,
199       Err(_e) => {
200         return Err(APIError::err(&self.op, "community_follower_already_exists"))?
201       }
202     };
203
204     // If its an admin, add them as a mod and follower to main
205     if data.admin {
206       let community_moderator_form = CommunityModeratorForm {
207         community_id: main_community.id,
208         user_id: inserted_user.id,
209       };
210
211       let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
212         Ok(user) => user,
213         Err(_e) => {
214           return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
215         }
216       };
217
218     }
219
220     // Return the jwt
221     Ok(
222       LoginResponse {
223         op: self.op.to_string(), 
224         jwt: inserted_user.jwt()
225       }
226       )
227   }
228 }
229
230 impl Perform<LoginResponse> for Oper<SaveUserSettings> {
231   fn perform(&self) -> Result<LoginResponse, Error> {
232     let data: &SaveUserSettings = &self.data;
233     let conn = establish_connection();
234
235     let claims = match Claims::decode(&data.auth) {
236       Ok(claims) => claims.claims,
237       Err(_e) => {
238         return Err(APIError::err(&self.op, "not_logged_in"))?
239       }
240     };
241
242     let user_id = claims.id;
243     
244     let read_user = User_::read(&conn, user_id)?;
245
246     let user_form = UserForm {
247       name: read_user.name,
248       fedi_name: read_user.fedi_name,
249       email: read_user.email,
250       password_encrypted: read_user.password_encrypted,
251       preferred_username: read_user.preferred_username,
252       updated: Some(naive_now()),
253       admin: read_user.admin,
254       banned: read_user.banned,
255       show_nsfw: data.show_nsfw,
256     };
257
258     let updated_user = match User_::update(&conn, user_id, &user_form) {
259       Ok(user) => user,
260       Err(_e) => {
261         return Err(APIError::err(&self.op, "couldnt_update_user"))?
262       }
263     };
264
265     // Return the jwt
266     Ok(
267       LoginResponse {
268         op: self.op.to_string(), 
269         jwt: updated_user.jwt()
270       }
271       )
272   }
273 }
274
275 impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
276   fn perform(&self) -> Result<GetUserDetailsResponse, Error> {
277     let data: &GetUserDetails = &self.data;
278     let conn = establish_connection();
279
280     let user_claims: Option<Claims> = match &data.auth {
281       Some(auth) => {
282         match Claims::decode(&auth) {
283           Ok(claims) => {
284             Some(claims.claims)
285           }
286           Err(_e) => None
287         }
288       }
289       None => None
290     };
291     
292     let user_id = match &user_claims {
293       Some(claims) => Some(claims.id),
294       None => None
295     };
296
297     let show_nsfw = match &user_claims {
298       Some(claims) => claims.show_nsfw,
299       None => false
300     };
301
302     //TODO add save
303     let sort = SortType::from_str(&data.sort)?;
304
305     let user_details_id = match data.user_id {
306       Some(id) => id,
307       None => User_::read_from_name(&conn, data.username.to_owned().unwrap_or("admin".to_string()))?.id
308     };
309
310     let user_view = UserView::read(&conn, user_details_id)?;
311
312     // If its saved only, you don't care what creator it was
313     let posts = if data.saved_only {
314       PostView::list(
315         &conn, 
316         PostListingType::All, 
317         &sort, 
318         data.community_id, 
319         None, 
320         None,
321         None,
322         Some(user_details_id), 
323         show_nsfw,
324         data.saved_only, 
325         false, 
326         data.page, 
327         data.limit)?
328     } else {
329       PostView::list(
330         &conn, 
331         PostListingType::All, 
332         &sort, 
333         data.community_id, 
334         Some(user_details_id), 
335         None, 
336         None,
337         user_id, 
338         show_nsfw,
339         data.saved_only, 
340         false, 
341         data.page, 
342         data.limit)?
343     };
344     let comments = if data.saved_only {
345       CommentView::list(
346         &conn, 
347         &sort, 
348         None, 
349         None, 
350         None, 
351         Some(user_details_id), 
352         data.saved_only, 
353         data.page, 
354         data.limit)?
355     } else {
356       CommentView::list(
357         &conn, 
358         &sort, 
359         None, 
360         Some(user_details_id), 
361         None, 
362         user_id, 
363         data.saved_only, 
364         data.page, 
365         data.limit)?
366     };
367
368     let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
369     let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
370
371     // Return the jwt
372     Ok(
373       GetUserDetailsResponse {
374         op: self.op.to_string(),
375         user: user_view,
376         follows: follows,
377         moderates: moderates, 
378         comments: comments,
379         posts: posts,
380       }
381       )
382   }
383 }
384
385
386 impl Perform<AddAdminResponse> for Oper<AddAdmin> {
387   fn perform(&self) -> Result<AddAdminResponse, Error> {
388     let data: &AddAdmin = &self.data;
389     let conn = establish_connection();
390
391     let claims = match Claims::decode(&data.auth) {
392       Ok(claims) => claims.claims,
393       Err(_e) => {
394         return Err(APIError::err(&self.op, "not_logged_in"))?
395       }
396     };
397
398     let user_id = claims.id;
399
400     // Make sure user is an admin
401     if UserView::read(&conn, user_id)?.admin == false {
402       return Err(APIError::err(&self.op, "not_an_admin"))?
403     }
404
405     let read_user = User_::read(&conn, data.user_id)?;
406
407     let user_form = UserForm {
408       name: read_user.name,
409       fedi_name: read_user.fedi_name,
410       email: read_user.email,
411       password_encrypted: read_user.password_encrypted,
412       preferred_username: read_user.preferred_username,
413       updated: Some(naive_now()),
414       admin: data.added,
415       banned: read_user.banned,
416       show_nsfw: read_user.show_nsfw,
417     };
418
419     match User_::update(&conn, data.user_id, &user_form) {
420       Ok(user) => user,
421       Err(_e) => {
422         return Err(APIError::err(&self.op, "couldnt_update_user"))?
423       }
424     };
425
426     // Mod tables
427     let form = ModAddForm {
428       mod_user_id: user_id,
429       other_user_id: data.user_id,
430       removed: Some(!data.added),
431     };
432
433     ModAdd::create(&conn, &form)?;
434
435     let site_creator_id = Site::read(&conn, 1)?.creator_id;
436     let mut admins = UserView::admins(&conn)?;
437     let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
438     let creator_user = admins.remove(creator_index);
439     admins.insert(0, creator_user);
440
441     Ok(
442       AddAdminResponse {
443         op: self.op.to_string(), 
444         admins: admins,
445       }
446       )
447   }
448 }
449
450 impl Perform<BanUserResponse> for Oper<BanUser> {
451   fn perform(&self) -> Result<BanUserResponse, Error> {
452     let data: &BanUser = &self.data;
453     let conn = establish_connection();
454
455     let claims = match Claims::decode(&data.auth) {
456       Ok(claims) => claims.claims,
457       Err(_e) => {
458         return Err(APIError::err(&self.op, "not_logged_in"))?
459       }
460     };
461
462     let user_id = claims.id;
463
464     // Make sure user is an admin
465     if UserView::read(&conn, user_id)?.admin == false {
466       return Err(APIError::err(&self.op, "not_an_admin"))?
467     }
468
469     let read_user = User_::read(&conn, data.user_id)?;
470
471     let user_form = UserForm {
472       name: read_user.name,
473       fedi_name: read_user.fedi_name,
474       email: read_user.email,
475       password_encrypted: read_user.password_encrypted,
476       preferred_username: read_user.preferred_username,
477       updated: Some(naive_now()),
478       admin: read_user.admin,
479       banned: data.ban,
480       show_nsfw: read_user.show_nsfw,
481     };
482
483     match User_::update(&conn, data.user_id, &user_form) {
484       Ok(user) => user,
485       Err(_e) => {
486         return Err(APIError::err(&self.op, "couldnt_update_user"))?
487       }
488     };
489
490     // Mod tables
491     let expires = match data.expires {
492       Some(time) => Some(naive_from_unix(time)),
493       None => None
494     };
495
496     let form = ModBanForm {
497       mod_user_id: user_id,
498       other_user_id: data.user_id,
499       reason: data.reason.to_owned(),
500       banned: Some(data.ban),
501       expires: expires,
502     };
503
504     ModBan::create(&conn, &form)?;
505
506     let user_view = UserView::read(&conn, data.user_id)?;
507
508     Ok(
509       BanUserResponse {
510         op: self.op.to_string(), 
511         user: user_view,
512         banned: data.ban
513       }
514       )
515
516   }
517 }
518
519 impl Perform<GetRepliesResponse> for Oper<GetReplies> {
520   fn perform(&self) -> Result<GetRepliesResponse, Error> {
521     let data: &GetReplies = &self.data;
522     let conn = establish_connection();
523
524     let claims = match Claims::decode(&data.auth) {
525       Ok(claims) => claims.claims,
526       Err(_e) => {
527         return Err(APIError::err(&self.op, "not_logged_in"))?
528       }
529     };
530
531     let user_id = claims.id;
532
533     let sort = SortType::from_str(&data.sort)?;
534
535     let replies = ReplyView::get_replies(&conn, user_id, &sort, data.unread_only, data.page, data.limit)?;
536
537     // Return the jwt
538     Ok(
539       GetRepliesResponse {
540         op: self.op.to_string(),
541         replies: replies,
542       }
543       )
544   }
545 }
546
547 impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
548   fn perform(&self) -> Result<GetRepliesResponse, Error> {
549     let data: &MarkAllAsRead = &self.data;
550     let conn = establish_connection();
551
552     let claims = match Claims::decode(&data.auth) {
553       Ok(claims) => claims.claims,
554       Err(_e) => {
555         return Err(APIError::err(&self.op, "not_logged_in"))?
556       }
557     };
558
559     let user_id = claims.id;
560
561     let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
562
563     for reply in &replies {
564       let comment_form = CommentForm {
565         content: reply.to_owned().content,
566         parent_id: reply.to_owned().parent_id,
567         post_id: reply.to_owned().post_id,
568         creator_id: reply.to_owned().creator_id,
569         removed: None,
570         deleted: None,
571         read: Some(true),
572         updated: reply.to_owned().updated 
573       };
574
575       let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
576         Ok(comment) => comment,
577         Err(_e) => {
578           return Err(APIError::err(&self.op, "couldnt_update_comment"))?
579         }
580       };
581     }
582
583     let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
584
585     Ok(
586       GetRepliesResponse {
587         op: self.op.to_string(),
588         replies: replies,
589       }
590       )
591   }
592 }