]> Untitled Git - lemmy.git/blob - server/src/api/post.rs
Spanish translations
[lemmy.git] / server / src / api / post.rs
1 use super::*;
2 use std::str::FromStr;
3
4 #[derive(Serialize, Deserialize)]
5 pub struct CreatePost {
6   name: String,
7   url: Option<String>,
8   body: Option<String>,
9   nsfw: bool,
10   community_id: i32,
11   auth: String,
12 }
13
14 #[derive(Serialize, Deserialize, Clone)]
15 pub struct PostResponse {
16   op: String,
17   pub post: PostView,
18 }
19
20 #[derive(Serialize, Deserialize)]
21 pub struct GetPost {
22   pub id: i32,
23   auth: Option<String>,
24 }
25
26 #[derive(Serialize, Deserialize)]
27 pub struct GetPostResponse {
28   op: String,
29   post: PostView,
30   comments: Vec<CommentView>,
31   community: CommunityView,
32   moderators: Vec<CommunityModeratorView>,
33   admins: Vec<UserView>,
34 }
35
36 #[derive(Serialize, Deserialize)]
37 pub struct GetPosts {
38   type_: String,
39   sort: String,
40   page: Option<i64>,
41   limit: Option<i64>,
42   community_id: Option<i32>,
43   auth: Option<String>,
44 }
45
46 #[derive(Serialize, Deserialize)]
47 pub struct GetPostsResponse {
48   op: String,
49   posts: Vec<PostView>,
50 }
51
52 #[derive(Serialize, Deserialize)]
53 pub struct CreatePostLike {
54   post_id: i32,
55   score: i16,
56   auth: String,
57 }
58
59 #[derive(Serialize, Deserialize)]
60 pub struct CreatePostLikeResponse {
61   op: String,
62   post: PostView,
63 }
64
65 #[derive(Serialize, Deserialize)]
66 pub struct EditPost {
67   pub edit_id: i32,
68   creator_id: i32,
69   community_id: i32,
70   name: String,
71   url: Option<String>,
72   body: Option<String>,
73   removed: Option<bool>,
74   deleted: Option<bool>,
75   nsfw: bool,
76   locked: Option<bool>,
77   stickied: Option<bool>,
78   reason: Option<String>,
79   auth: String,
80 }
81
82 #[derive(Serialize, Deserialize)]
83 pub struct SavePost {
84   post_id: i32,
85   save: bool,
86   auth: String,
87 }
88
89 impl Perform<PostResponse> for Oper<CreatePost> {
90   fn perform(&self) -> Result<PostResponse, Error> {
91     let data: &CreatePost = &self.data;
92     let conn = establish_connection();
93
94     let claims = match Claims::decode(&data.auth) {
95       Ok(claims) => claims.claims,
96       Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
97     };
98
99     if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
100       return Err(APIError::err(&self.op, "no_slurs"))?;
101     }
102
103     let user_id = claims.id;
104
105     // Check for a community ban
106     if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() {
107       return Err(APIError::err(&self.op, "community_ban"))?;
108     }
109
110     // Check for a site ban
111     if UserView::read(&conn, user_id)?.banned {
112       return Err(APIError::err(&self.op, "site_ban"))?;
113     }
114
115     let post_form = PostForm {
116       name: data.name.to_owned(),
117       url: data.url.to_owned(),
118       body: data.body.to_owned(),
119       community_id: data.community_id,
120       creator_id: user_id,
121       removed: None,
122       deleted: None,
123       nsfw: data.nsfw,
124       locked: None,
125       stickied: None,
126       updated: None,
127     };
128
129     let inserted_post = match Post::create(&conn, &post_form) {
130       Ok(post) => post,
131       Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_post"))?,
132     };
133
134     // They like their own post by default
135     let like_form = PostLikeForm {
136       post_id: inserted_post.id,
137       user_id: user_id,
138       score: 1,
139     };
140
141     // Only add the like if the score isnt 0
142     let _inserted_like = match PostLike::like(&conn, &like_form) {
143       Ok(like) => like,
144       Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
145     };
146
147     // Refetch the view
148     let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
149       Ok(post) => post,
150       Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
151     };
152
153     Ok(PostResponse {
154       op: self.op.to_string(),
155       post: post_view,
156     })
157   }
158 }
159
160 impl Perform<GetPostResponse> for Oper<GetPost> {
161   fn perform(&self) -> Result<GetPostResponse, Error> {
162     let data: &GetPost = &self.data;
163     let conn = establish_connection();
164
165     let user_id: Option<i32> = match &data.auth {
166       Some(auth) => match Claims::decode(&auth) {
167         Ok(claims) => {
168           let user_id = claims.claims.id;
169           Some(user_id)
170         }
171         Err(_e) => None,
172       },
173       None => None,
174     };
175
176     let post_view = match PostView::read(&conn, data.id, user_id) {
177       Ok(post) => post,
178       Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
179     };
180
181     let comments = CommentView::list(
182       &conn,
183       &SortType::New,
184       Some(data.id),
185       None,
186       None,
187       user_id,
188       false,
189       None,
190       Some(9999),
191     )?;
192
193     let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
194
195     let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
196
197     let site_creator_id = Site::read(&conn, 1)?.creator_id;
198     let mut admins = UserView::admins(&conn)?;
199     let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
200     let creator_user = admins.remove(creator_index);
201     admins.insert(0, creator_user);
202
203     // Return the jwt
204     Ok(GetPostResponse {
205       op: self.op.to_string(),
206       post: post_view,
207       comments: comments,
208       community: community,
209       moderators: moderators,
210       admins: admins,
211     })
212   }
213 }
214
215 impl Perform<GetPostsResponse> for Oper<GetPosts> {
216   fn perform(&self) -> Result<GetPostsResponse, Error> {
217     let data: &GetPosts = &self.data;
218     let conn = establish_connection();
219
220     let user_claims: Option<Claims> = match &data.auth {
221       Some(auth) => match Claims::decode(&auth) {
222         Ok(claims) => Some(claims.claims),
223         Err(_e) => None,
224       },
225       None => None,
226     };
227
228     let user_id = match &user_claims {
229       Some(claims) => Some(claims.id),
230       None => None,
231     };
232
233     let show_nsfw = match &user_claims {
234       Some(claims) => claims.show_nsfw,
235       None => false,
236     };
237
238     let type_ = PostListingType::from_str(&data.type_)?;
239     let sort = SortType::from_str(&data.sort)?;
240
241     let posts = match PostView::list(
242       &conn,
243       type_,
244       &sort,
245       data.community_id,
246       None,
247       None,
248       None,
249       user_id,
250       show_nsfw,
251       false,
252       false,
253       data.page,
254       data.limit,
255     ) {
256       Ok(posts) => posts,
257       Err(_e) => return Err(APIError::err(&self.op, "couldnt_get_posts"))?,
258     };
259
260     Ok(GetPostsResponse {
261       op: self.op.to_string(),
262       posts: posts,
263     })
264   }
265 }
266
267 impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
268   fn perform(&self) -> Result<CreatePostLikeResponse, Error> {
269     let data: &CreatePostLike = &self.data;
270     let conn = establish_connection();
271
272     let claims = match Claims::decode(&data.auth) {
273       Ok(claims) => claims.claims,
274       Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
275     };
276
277     let user_id = claims.id;
278
279     // Check for a community ban
280     let post = Post::read(&conn, data.post_id)?;
281     if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
282       return Err(APIError::err(&self.op, "community_ban"))?;
283     }
284
285     // Check for a site ban
286     if UserView::read(&conn, user_id)?.banned {
287       return Err(APIError::err(&self.op, "site_ban"))?;
288     }
289
290     let like_form = PostLikeForm {
291       post_id: data.post_id,
292       user_id: user_id,
293       score: data.score,
294     };
295
296     // Remove any likes first
297     PostLike::remove(&conn, &like_form)?;
298
299     // Only add the like if the score isnt 0
300     let do_add = &like_form.score != &0 && (&like_form.score == &1 || &like_form.score == &-1);
301     if do_add {
302       let _inserted_like = match PostLike::like(&conn, &like_form) {
303         Ok(like) => like,
304         Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
305       };
306     }
307
308     let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) {
309       Ok(post) => post,
310       Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
311     };
312
313     // just output the score
314     Ok(CreatePostLikeResponse {
315       op: self.op.to_string(),
316       post: post_view,
317     })
318   }
319 }
320
321 impl Perform<PostResponse> for Oper<EditPost> {
322   fn perform(&self) -> Result<PostResponse, Error> {
323     let data: &EditPost = &self.data;
324     if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
325       return Err(APIError::err(&self.op, "no_slurs"))?;
326     }
327
328     let conn = establish_connection();
329
330     let claims = match Claims::decode(&data.auth) {
331       Ok(claims) => claims.claims,
332       Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
333     };
334
335     let user_id = claims.id;
336
337     // Verify its the creator or a mod or admin
338     let mut editors: Vec<i32> = vec![data.creator_id];
339     editors.append(
340       &mut CommunityModeratorView::for_community(&conn, data.community_id)?
341         .into_iter()
342         .map(|m| m.user_id)
343         .collect(),
344     );
345     editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
346     if !editors.contains(&user_id) {
347       return Err(APIError::err(&self.op, "no_post_edit_allowed"))?;
348     }
349
350     // Check for a community ban
351     if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() {
352       return Err(APIError::err(&self.op, "community_ban"))?;
353     }
354
355     // Check for a site ban
356     if UserView::read(&conn, user_id)?.banned {
357       return Err(APIError::err(&self.op, "site_ban"))?;
358     }
359
360     let post_form = PostForm {
361       name: data.name.to_owned(),
362       url: data.url.to_owned(),
363       body: data.body.to_owned(),
364       creator_id: data.creator_id.to_owned(),
365       community_id: data.community_id,
366       removed: data.removed.to_owned(),
367       deleted: data.deleted.to_owned(),
368       nsfw: data.nsfw,
369       locked: data.locked.to_owned(),
370       stickied: data.stickied.to_owned(),
371       updated: Some(naive_now()),
372     };
373
374     let _updated_post = match Post::update(&conn, data.edit_id, &post_form) {
375       Ok(post) => post,
376       Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post"))?,
377     };
378
379     // Mod tables
380     if let Some(removed) = data.removed.to_owned() {
381       let form = ModRemovePostForm {
382         mod_user_id: user_id,
383         post_id: data.edit_id,
384         removed: Some(removed),
385         reason: data.reason.to_owned(),
386       };
387       ModRemovePost::create(&conn, &form)?;
388     }
389
390     if let Some(locked) = data.locked.to_owned() {
391       let form = ModLockPostForm {
392         mod_user_id: user_id,
393         post_id: data.edit_id,
394         locked: Some(locked),
395       };
396       ModLockPost::create(&conn, &form)?;
397     }
398
399     if let Some(stickied) = data.stickied.to_owned() {
400       let form = ModStickyPostForm {
401         mod_user_id: user_id,
402         post_id: data.edit_id,
403         stickied: Some(stickied),
404       };
405       ModStickyPost::create(&conn, &form)?;
406     }
407
408     let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
409
410     Ok(PostResponse {
411       op: self.op.to_string(),
412       post: post_view,
413     })
414   }
415 }
416
417 impl Perform<PostResponse> for Oper<SavePost> {
418   fn perform(&self) -> Result<PostResponse, Error> {
419     let data: &SavePost = &self.data;
420     let conn = establish_connection();
421
422     let claims = match Claims::decode(&data.auth) {
423       Ok(claims) => claims.claims,
424       Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
425     };
426
427     let user_id = claims.id;
428
429     let post_saved_form = PostSavedForm {
430       post_id: data.post_id,
431       user_id: user_id,
432     };
433
434     if data.save {
435       match PostSaved::save(&conn, &post_saved_form) {
436         Ok(post) => post,
437         Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
438       };
439     } else {
440       match PostSaved::unsave(&conn, &post_saved_form) {
441         Ok(post) => post,
442         Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
443       };
444     }
445
446     let post_view = PostView::read(&conn, data.post_id, Some(user_id))?;
447
448     Ok(PostResponse {
449       op: self.op.to_string(),
450       post: post_view,
451     })
452   }
453 }