4 #[derive(Serialize, Deserialize)]
5 pub struct CreatePost {
14 #[derive(Serialize, Deserialize, Clone)]
15 pub struct PostResponse {
20 #[derive(Serialize, Deserialize)]
26 #[derive(Serialize, Deserialize)]
27 pub struct GetPostResponse {
30 comments: Vec<CommentView>,
31 community: CommunityView,
32 moderators: Vec<CommunityModeratorView>,
33 admins: Vec<UserView>,
36 #[derive(Serialize, Deserialize)]
42 community_id: Option<i32>,
46 #[derive(Serialize, Deserialize)]
47 pub struct GetPostsResponse {
52 #[derive(Serialize, Deserialize)]
53 pub struct CreatePostLike {
59 #[derive(Serialize, Deserialize)]
60 pub struct CreatePostLikeResponse {
65 #[derive(Serialize, Deserialize)]
73 removed: Option<bool>,
74 deleted: Option<bool>,
77 stickied: Option<bool>,
78 reason: Option<String>,
82 #[derive(Serialize, Deserialize)]
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();
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"))?,
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"))?;
103 let user_id = claims.id;
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"))?;
110 // Check for a site ban
111 if UserView::read(&conn, user_id)?.banned {
112 return Err(APIError::err(&self.op, "site_ban"))?;
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,
129 let inserted_post = match Post::create(&conn, &post_form) {
131 Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_post"))?,
134 // They like their own post by default
135 let like_form = PostLikeForm {
136 post_id: inserted_post.id,
141 // Only add the like if the score isnt 0
142 let _inserted_like = match PostLike::like(&conn, &like_form) {
144 Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
148 let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
150 Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
154 op: self.op.to_string(),
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();
165 let user_id: Option<i32> = match &data.auth {
166 Some(auth) => match Claims::decode(&auth) {
168 let user_id = claims.claims.id;
176 let post_view = match PostView::read(&conn, data.id, user_id) {
178 Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
181 let comments = CommentView::list(
193 let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
195 let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
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);
205 op: self.op.to_string(),
208 community: community,
209 moderators: moderators,
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();
220 let user_claims: Option<Claims> = match &data.auth {
221 Some(auth) => match Claims::decode(&auth) {
222 Ok(claims) => Some(claims.claims),
228 let user_id = match &user_claims {
229 Some(claims) => Some(claims.id),
233 let show_nsfw = match &user_claims {
234 Some(claims) => claims.show_nsfw,
238 let type_ = PostListingType::from_str(&data.type_)?;
239 let sort = SortType::from_str(&data.sort)?;
241 let posts = match PostView::list(
257 Err(_e) => return Err(APIError::err(&self.op, "couldnt_get_posts"))?,
260 Ok(GetPostsResponse {
261 op: self.op.to_string(),
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();
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"))?,
277 let user_id = claims.id;
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"))?;
285 // Check for a site ban
286 if UserView::read(&conn, user_id)?.banned {
287 return Err(APIError::err(&self.op, "site_ban"))?;
290 let like_form = PostLikeForm {
291 post_id: data.post_id,
296 // Remove any likes first
297 PostLike::remove(&conn, &like_form)?;
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);
302 let _inserted_like = match PostLike::like(&conn, &like_form) {
304 Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
308 let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) {
310 Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
313 // just output the score
314 Ok(CreatePostLikeResponse {
315 op: self.op.to_string(),
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"))?;
328 let conn = establish_connection();
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"))?,
335 let user_id = claims.id;
337 // Verify its the creator or a mod or admin
338 let mut editors: Vec<i32> = vec![data.creator_id];
340 &mut CommunityModeratorView::for_community(&conn, data.community_id)?
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"))?;
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"))?;
355 // Check for a site ban
356 if UserView::read(&conn, user_id)?.banned {
357 return Err(APIError::err(&self.op, "site_ban"))?;
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(),
369 locked: data.locked.to_owned(),
370 stickied: data.stickied.to_owned(),
371 updated: Some(naive_now()),
374 let _updated_post = match Post::update(&conn, data.edit_id, &post_form) {
376 Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post"))?,
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(),
387 ModRemovePost::create(&conn, &form)?;
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),
396 ModLockPost::create(&conn, &form)?;
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),
405 ModStickyPost::create(&conn, &form)?;
408 let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
411 op: self.op.to_string(),
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();
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"))?,
427 let user_id = claims.id;
429 let post_saved_form = PostSavedForm {
430 post_id: data.post_id,
435 match PostSaved::save(&conn, &post_saved_form) {
437 Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
440 match PostSaved::unsave(&conn, &post_saved_form) {
442 Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
446 let post_view = PostView::read(&conn, data.post_id, Some(user_id))?;
449 op: self.op.to_string(),