]> 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 }
19
20 #[derive(Serialize, Deserialize)]
21 pub struct LoginResponse {
22   op: String,
23   jwt: String
24 }
25
26 #[derive(Serialize, Deserialize)]
27 pub struct GetUserDetails {
28   user_id: Option<i32>,
29   username: Option<String>,
30   sort: String,
31   page: Option<i64>,
32   limit: Option<i64>,
33   community_id: Option<i32>,
34   saved_only: bool,
35   auth: Option<String>,
36 }
37
38 #[derive(Serialize, Deserialize)]
39 pub struct GetUserDetailsResponse {
40   op: String,
41   user: UserView,
42   follows: Vec<CommunityFollowerView>,
43   moderates: Vec<CommunityModeratorView>,
44   comments: Vec<CommentView>,
45   posts: Vec<PostView>,
46 }
47
48 #[derive(Serialize, Deserialize)]
49 pub struct GetRepliesResponse {
50   op: String,
51   replies: Vec<ReplyView>,
52 }
53
54 #[derive(Serialize, Deserialize)]
55 pub struct MarkAllAsRead {
56   auth: String
57 }
58
59 #[derive(Serialize, Deserialize)]
60 pub struct AddAdmin {
61   user_id: i32,
62   added: bool,
63   auth: String
64 }
65
66 #[derive(Serialize, Deserialize)]
67 pub struct AddAdminResponse {
68   op: String,
69   admins: Vec<UserView>,
70 }
71
72 #[derive(Serialize, Deserialize)]
73 pub struct BanUser {
74   user_id: i32,
75   ban: bool,
76   reason: Option<String>,
77   expires: Option<i64>,
78   auth: String
79 }
80
81 #[derive(Serialize, Deserialize)]
82 pub struct BanUserResponse {
83   op: String,
84   user: UserView,
85   banned: bool,
86 }
87
88 #[derive(Serialize, Deserialize)]
89 pub struct GetReplies {
90   sort: String,
91   page: Option<i64>,
92   limit: Option<i64>,
93   unread_only: bool,
94   auth: String
95 }
96
97 impl Perform<LoginResponse> for Oper<Login> {
98   fn perform(&self) -> Result<LoginResponse, Error> {
99     let data: &Login = &self.data;
100     let conn = establish_connection();
101
102     // Fetch that username / email
103     let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) {
104       Ok(user) => user,
105       Err(_e) => return Err(APIError::err(&self.op, "Couldn't find that username or email"))?
106     };
107
108     // Verify the password
109     let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
110     if !valid {
111       return Err(APIError::err(&self.op, "Password incorrect"))?
112     }
113
114     // Return the jwt
115     Ok(
116       LoginResponse {
117         op: self.op.to_string(),
118         jwt: user.jwt()
119       }
120       )
121   }
122 }
123
124
125 impl Perform<LoginResponse> for Oper<Register> {
126   fn perform(&self) -> Result<LoginResponse, Error> {
127     let data: &Register = &self.data;
128     let conn = establish_connection();
129
130     // Make sure passwords match
131     if &data.password != &data.password_verify {
132       return Err(APIError::err(&self.op, "Passwords do not match."))?
133     }
134
135     if has_slurs(&data.username) {
136       return Err(APIError::err(&self.op, "No slurs"))?
137     }
138
139     // Make sure there are no admins
140     if data.admin && UserView::admins(&conn)?.len() > 0 {
141       return Err(APIError::err(&self.op, "Sorry, there's already an admin."))?
142     }
143
144     // Register the new user
145     let user_form = UserForm {
146       name: data.username.to_owned(),
147       fedi_name: Settings::get().hostname.into(),
148       email: data.email.to_owned(),
149       password_encrypted: data.password.to_owned(),
150       preferred_username: None,
151       updated: None,
152       admin: data.admin,
153       banned: false,
154     };
155
156     // Create the user
157     let inserted_user = match User_::register(&conn, &user_form) {
158       Ok(user) => user,
159       Err(_e) => {
160         return Err(APIError::err(&self.op, "User already exists."))?
161       }
162     };
163
164     // Sign them up for main community no matter what
165     let community_follower_form = CommunityFollowerForm {
166       community_id: 1,
167       user_id: inserted_user.id,
168     };
169
170     let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
171       Ok(user) => user,
172       Err(_e) => {
173         return Err(APIError::err(&self.op, "Community follower already exists."))?
174       }
175     };
176
177     // If its an admin, add them as a mod and follower to main
178     if data.admin {
179       let community_moderator_form = CommunityModeratorForm {
180         community_id: 1,
181         user_id: inserted_user.id,
182       };
183
184       let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
185         Ok(user) => user,
186         Err(_e) => {
187           return Err(APIError::err(&self.op, "Community moderator already exists."))?
188         }
189       };
190
191     }
192
193     // Return the jwt
194     Ok(
195       LoginResponse {
196         op: self.op.to_string(), 
197         jwt: inserted_user.jwt()
198       }
199       )
200   }
201 }
202
203
204 impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
205   fn perform(&self) -> Result<GetUserDetailsResponse, Error> {
206     let data: &GetUserDetails = &self.data;
207     let conn = establish_connection();
208
209     let user_id: Option<i32> = match &data.auth {
210       Some(auth) => {
211         match Claims::decode(&auth) {
212           Ok(claims) => {
213             let user_id = claims.claims.id;
214             Some(user_id)
215           }
216           Err(_e) => None
217         }
218       }
219       None => None
220     };
221
222     //TODO add save
223     let sort = SortType::from_str(&data.sort)?;
224
225     let user_details_id = match data.user_id {
226       Some(id) => id,
227       None => User_::read_from_name(&conn, data.username.to_owned().unwrap_or("admin".to_string()))?.id
228     };
229
230     let user_view = UserView::read(&conn, user_details_id)?;
231
232     // If its saved only, you don't care what creator it was
233     let posts = if data.saved_only {
234       PostView::list(&conn, 
235                      PostListingType::All, 
236                      &sort, 
237                      data.community_id, 
238                      None, 
239                      None,
240                      Some(user_details_id), 
241                      data.saved_only, 
242                      false, 
243                      data.page, 
244                      data.limit)?
245     } else {
246       PostView::list(&conn, 
247                      PostListingType::All, 
248                      &sort, 
249                      data.community_id, 
250                      Some(user_details_id), 
251                      None, 
252                      user_id, 
253                      data.saved_only, 
254                      false, 
255                      data.page, 
256                      data.limit)?
257     };
258     let comments = if data.saved_only {
259       CommentView::list(&conn, 
260                         &sort, 
261                         None, 
262                         None, 
263                         None, 
264                         Some(user_details_id), 
265                         data.saved_only, 
266                         data.page, 
267                         data.limit)?
268     } else {
269       CommentView::list(&conn, 
270                         &sort, 
271                         None, 
272                         Some(user_details_id), 
273                         None, 
274                         user_id, 
275                         data.saved_only, 
276                         data.page, 
277                         data.limit)?
278     };
279
280     let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
281     let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
282
283     // Return the jwt
284     Ok(
285       GetUserDetailsResponse {
286         op: self.op.to_string(),
287         user: user_view,
288         follows: follows,
289         moderates: moderates, 
290         comments: comments,
291         posts: posts,
292       }
293       )
294   }
295 }
296
297
298 impl Perform<AddAdminResponse> for Oper<AddAdmin> {
299   fn perform(&self) -> Result<AddAdminResponse, Error> {
300     let data: &AddAdmin = &self.data;
301     let conn = establish_connection();
302
303     let claims = match Claims::decode(&data.auth) {
304       Ok(claims) => claims.claims,
305       Err(_e) => {
306         return Err(APIError::err(&self.op, "Not logged in."))?
307       }
308     };
309
310     let user_id = claims.id;
311
312     // Make sure user is an admin
313     if UserView::read(&conn, user_id)?.admin == false {
314       return Err(APIError::err(&self.op, "Not an admin."))?
315     }
316
317     let read_user = User_::read(&conn, data.user_id)?;
318
319     let user_form = UserForm {
320       name: read_user.name,
321       fedi_name: read_user.fedi_name,
322       email: read_user.email,
323       password_encrypted: read_user.password_encrypted,
324       preferred_username: read_user.preferred_username,
325       updated: Some(naive_now()),
326       admin: data.added,
327       banned: read_user.banned,
328     };
329
330     match User_::update(&conn, data.user_id, &user_form) {
331       Ok(user) => user,
332       Err(_e) => {
333         return Err(APIError::err(&self.op, "Couldn't update user"))?
334       }
335     };
336
337     // Mod tables
338     let form = ModAddForm {
339       mod_user_id: user_id,
340       other_user_id: data.user_id,
341       removed: Some(!data.added),
342     };
343
344     ModAdd::create(&conn, &form)?;
345
346     let admins = UserView::admins(&conn)?;
347
348     Ok(
349       AddAdminResponse {
350         op: self.op.to_string(), 
351         admins: admins,
352       }
353       )
354   }
355 }
356
357 impl Perform<BanUserResponse> for Oper<BanUser> {
358   fn perform(&self) -> Result<BanUserResponse, Error> {
359     let data: &BanUser = &self.data;
360     let conn = establish_connection();
361
362     let claims = match Claims::decode(&data.auth) {
363       Ok(claims) => claims.claims,
364       Err(_e) => {
365         return Err(APIError::err(&self.op, "Not logged in."))?
366       }
367     };
368
369     let user_id = claims.id;
370
371     // Make sure user is an admin
372     if UserView::read(&conn, user_id)?.admin == false {
373       return Err(APIError::err(&self.op, "Not an admin."))?
374     }
375
376     let read_user = User_::read(&conn, data.user_id)?;
377
378     let user_form = UserForm {
379       name: read_user.name,
380       fedi_name: read_user.fedi_name,
381       email: read_user.email,
382       password_encrypted: read_user.password_encrypted,
383       preferred_username: read_user.preferred_username,
384       updated: Some(naive_now()),
385       admin: read_user.admin,
386       banned: data.ban,
387     };
388
389     match User_::update(&conn, data.user_id, &user_form) {
390       Ok(user) => user,
391       Err(_e) => {
392         return Err(APIError::err(&self.op, "Couldn't update user"))?
393       }
394     };
395
396     // Mod tables
397     let expires = match data.expires {
398       Some(time) => Some(naive_from_unix(time)),
399       None => None
400     };
401
402     let form = ModBanForm {
403       mod_user_id: user_id,
404       other_user_id: data.user_id,
405       reason: data.reason.to_owned(),
406       banned: Some(data.ban),
407       expires: expires,
408     };
409
410     ModBan::create(&conn, &form)?;
411
412     let user_view = UserView::read(&conn, data.user_id)?;
413
414     Ok(
415       BanUserResponse {
416         op: self.op.to_string(), 
417         user: user_view,
418         banned: data.ban
419       }
420       )
421
422   }
423 }
424
425 impl Perform<GetRepliesResponse> for Oper<GetReplies> {
426   fn perform(&self) -> Result<GetRepliesResponse, Error> {
427     let data: &GetReplies = &self.data;
428     let conn = establish_connection();
429
430     let claims = match Claims::decode(&data.auth) {
431       Ok(claims) => claims.claims,
432       Err(_e) => {
433         return Err(APIError::err(&self.op, "Not logged in."))?
434       }
435     };
436
437     let user_id = claims.id;
438
439     let sort = SortType::from_str(&data.sort)?;
440
441     let replies = ReplyView::get_replies(&conn, user_id, &sort, data.unread_only, data.page, data.limit)?;
442
443     // Return the jwt
444     Ok(
445       GetRepliesResponse {
446         op: self.op.to_string(),
447         replies: replies,
448       }
449       )
450   }
451 }
452
453 impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
454   fn perform(&self) -> Result<GetRepliesResponse, Error> {
455     let data: &MarkAllAsRead = &self.data;
456     let conn = establish_connection();
457
458     let claims = match Claims::decode(&data.auth) {
459       Ok(claims) => claims.claims,
460       Err(_e) => {
461         return Err(APIError::err(&self.op, "Not logged in."))?
462       }
463     };
464
465     let user_id = claims.id;
466
467     let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
468
469     for reply in &replies {
470       let comment_form = CommentForm {
471         content: reply.to_owned().content,
472         parent_id: reply.to_owned().parent_id,
473         post_id: reply.to_owned().post_id,
474         creator_id: reply.to_owned().creator_id,
475         removed: None,
476         deleted: None,
477         read: Some(true),
478         updated: reply.to_owned().updated 
479       };
480
481       let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
482         Ok(comment) => comment,
483         Err(_e) => {
484           return Err(APIError::err(&self.op, "Couldn't update Comment"))?
485         }
486       };
487     }
488
489     let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
490
491     Ok(
492       GetRepliesResponse {
493         op: self.op.to_string(),
494         replies: replies,
495       }
496       )
497   }
498 }