]> Untitled Git - lemmy.git/commitdiff
reports: update db tables, combine api impl
authoreiknat <eiknat@protonmail.com>
Wed, 21 Oct 2020 00:31:01 +0000 (20:31 -0400)
committereiknat <eiknat@dev.chapo.chat>
Wed, 11 Nov 2020 20:11:52 +0000 (15:11 -0500)
14 files changed:
Cargo.lock
lemmy_api/src/lib.rs
lemmy_api/src/report.rs
lemmy_db/Cargo.toml
lemmy_db/src/comment_report.rs
lemmy_db/src/lib.rs
lemmy_db/src/post_report.rs
lemmy_db/src/schema.rs
lemmy_structs/Cargo.toml
lemmy_structs/src/report.rs
lemmy_websocket/src/lib.rs
migrations/2020-10-13-212240_create_report_tables/down.sql
migrations/2020-10-13-212240_create_report_tables/up.sql
src/routes/api.rs

index 8abe539bb26b4e5797222defe25da340d1540fb8..c5f9847837f4280bc0345e97c559f6c0f4a079da 100644 (file)
@@ -1054,7 +1054,6 @@ dependencies = [
  "pq-sys",
  "r2d2",
  "serde_json",
- "uuid 0.6.5",
 ]
 
 [[package]]
@@ -1834,7 +1833,6 @@ dependencies = [
  "strum",
  "strum_macros",
  "url",
- "uuid 0.6.5",
 ]
 
 [[package]]
@@ -1900,7 +1898,6 @@ dependencies = [
  "log",
  "serde 1.0.117",
  "serde_json",
- "uuid 0.6.5",
 ]
 
 [[package]]
index 6b35f6750669cd38639e44e06ab24b0cf4d3f654..5920918bfd2ed0a9c574b65ae76aa809baf71668 100644 (file)
@@ -267,15 +267,6 @@ pub async fn match_websocket_operation(
       do_websocket_operation::<CreatePostLike>(context, id, op, data).await
     }
     UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
-    UserOperation::CreatePostReport => {
-      do_websocket_operation::<CreatePostReport>(context, id, op, data).await
-    }
-    UserOperation::ListPostReports => {
-      do_websocket_operation::<ListPostReports>(context, id, op, data).await
-    }
-    UserOperation::ResolvePostReport => {
-      do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
-    }
 
     // Comment ops
     UserOperation::CreateComment => {
@@ -302,14 +293,16 @@ pub async fn match_websocket_operation(
     UserOperation::CreateCommentLike => {
       do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
     }
-    UserOperation::CreateCommentReport => {
-      do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
-    },
-    UserOperation::ListCommentReports => {
-      do_websocket_operation::<ListCommentReports>(context, id, op, data).await
-    },
-    UserOperation::ResolveCommentReport => {
-      do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
+
+    // report ops
+    UserOperation::CreateReport => {
+      do_websocket_operation::<CreateReport>(context, id, op, data).await
+    }
+    UserOperation::ListReports => {
+      do_websocket_operation::<ListReports>(context, id, op, data).await
+    }
+    UserOperation::ResolveReport => {
+      do_websocket_operation::<ResolveReport>(context, id, op, data).await
     }
     UserOperation::GetReportCount => {
       do_websocket_operation::<GetReportCount>(context, id, op, data).await
index f5557500e367f77107b02a899f8d476545b08941..5088eaa3eb95b6d3892ee5d6d6f975c7302f316c 100644 (file)
 use actix_web::web::Data;
+use std::str::FromStr;
 
-use lemmy_db::{
-  comment_report::*,
-  comment_view::*,
-  community_view::*,
-  post_report::*,
-  post_view::*,
-  Reportable,
-  user_view::UserView,
-};
+use lemmy_db::{comment_report::*, comment_view::*, post_report::*, post_view::*, Reportable, ReportType,};
 use lemmy_structs::{blocking, report::*};
 use lemmy_utils::{APIError, ConnectionId, LemmyError};
-use lemmy_websocket::LemmyContext;
+use lemmy_websocket::{LemmyContext, UserOperation, messages::SendUserRoomMessage};
 
-use crate::{check_community_ban, get_user_from_jwt, Perform};
+use crate::{check_community_ban, get_user_from_jwt, is_mod_or_admin, Perform};
 
 const MAX_REPORT_LEN: usize = 1000;
 
 #[async_trait::async_trait(?Send)]
-impl Perform for CreateCommentReport {
-  type Response = CommentReportResponse;
+impl Perform for CreateReport {
+  type Response = CreateReportResponse;
 
   async fn perform(
     &self,
     context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
-  ) -> Result<CommentReportResponse, LemmyError> {
-    let data: &CreateCommentReport = &self;
+    websocket_id: Option<ConnectionId>,
+  ) -> Result<CreateReportResponse, LemmyError> {
+    let data: &CreateReport = &self;
     let user = get_user_from_jwt(&data.auth, context.pool()).await?;
-    
-    // Check size of report and check for whitespace
-    let reason: Option<String> = match data.reason.clone() {
-      Some(s) if s.trim().is_empty() => None,
-      Some(s) if s.len() > MAX_REPORT_LEN => {
-        return Err(APIError::err("report_too_long").into());
-      }
-      Some(s) => Some(s),
-      None => None,
-    };
-
-    // Fetch comment information
-    let comment_id = data.comment;
-    let comment = blocking(context.pool(), move |conn| CommentView::read(&conn, comment_id, None)).await??;
-
-    // Check for community ban
-    check_community_ban(user.id, comment.community_id, context.pool()).await?;
-
-    // Insert the report
-    let comment_time = match comment.updated {
-      Some(s) => s,
-      None => comment.published,
-    };
-    let report_form = CommentReportForm {
-      time: None, // column defaults to now() in table
-      reason,
-      resolved: None, // column defaults to false
-      user_id: user.id,
-      comment_id,
-      comment_text: comment.content,
-      comment_time,
-    };
-    blocking(context.pool(), move |conn| CommentReport::report(conn, &report_form)).await??;
-
-    Ok(CommentReportResponse { success: true })
-  }
-}
-
-#[async_trait::async_trait(?Send)]
-impl Perform for CreatePostReport {
-  type Response = PostReportResponse;
 
-  async fn perform(
-    &self,
-    context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
-  ) -> Result<PostReportResponse, LemmyError> {
-    let data: &CreatePostReport = &self;
-    let user = get_user_from_jwt(&data.auth, context.pool()).await?;
+    // check size of report and check for whitespace
+    let reason = data.reason.clone();
+    if reason.trim().is_empty() {
+      return Err(APIError::err("report_reason_required").into());
+    }
+    if reason.len() > MAX_REPORT_LEN {
+      return Err(APIError::err("report_too_long").into());
+    }
 
-    // Check size of report and check for whitespace
-    let reason: Option<String> = match data.reason.clone() {
-      Some(s) if s.trim().is_empty() => None,
-      Some(s) if s.len() > MAX_REPORT_LEN => {
-        return Err(APIError::err("report_too_long").into());
-      }
-      Some(s) => Some(s),
-      None => None,
-    };
+    let report_type = ReportType::from_str(&data.report_type)?;
+    let user_id = user.id;
+    match report_type {
+      ReportType::Comment => { create_comment_report(context, data, user_id).await?; }
+      ReportType::Post => { create_post_report(context, data, user_id).await?; }
+    }
 
-    // Fetch post information from the database
-    let post_id = data.post;
-    let post = blocking(context.pool(), move |conn| PostView::read(&conn, post_id, None)).await??;
+    // to build on this, the user should get a success response, however
+    // mods should get a different response with more details
+    let res = CreateReportResponse { success: true };
 
-    // Check for community ban
-    check_community_ban(user.id, post.community_id, context.pool()).await?;
+    context.chat_server().do_send(SendUserRoomMessage {
+      op: UserOperation::CreateReport,
+      response: res.clone(),
+      recipient_id: user.id,
+      websocket_id,
+    });
 
-    // Insert the report
-    let post_time = match post.updated {
-      Some(s) => s,
-      None => post.published,
-    };
-    let report_form = PostReportForm {
-      time: None, // column defaults to now() in table
-      reason,
-      resolved: None, // column defaults to false
-      user_id: user.id,
-      post_id,
-      post_name: post.name,
-      post_url: post.url,
-      post_body: post.body,
-      post_time,
-    };
-    blocking(context.pool(), move |conn| PostReport::report(conn, &report_form)).await??;
-
-    Ok(PostReportResponse { success: true })
+    Ok(res)
   }
 }
 
@@ -124,39 +60,14 @@ impl Perform for GetReportCount {
   async fn perform(
     &self,
     context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
+    websocket_id: Option<ConnectionId>,
   ) -> Result<GetReportCountResponse, LemmyError> {
     let data: &GetReportCount = &self;
     let user = get_user_from_jwt(&data.auth, context.pool()).await?;
-
     let community_id = data.community;
-    //Check community exists.
-    let community_id = blocking(context.pool(), move |conn| {
-      CommunityView::read(conn, community_id, None)
-    })
-    .await??
-    .id;
-
-    // Check community ban
-    check_community_ban(user.id, data.community, context.pool()).await?;
-
-    let mut mod_ids: Vec<i32> = Vec::new();
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        CommunityModeratorView::for_community(conn, community_id)
-          .map(|v| v.into_iter().map(|m| m.user_id).collect())
-      })
-      .await??,
-    );
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())
-      })
-      .await??,
-    );
-    if !mod_ids.contains(&user.id) {
-      return Err(APIError::err("report_view_not_allowed").into());
-    }
+
+    // Check for mod/admin privileges
+    is_mod_or_admin(context.pool(), user.id, community_id).await?;
 
     let comment_reports = blocking(context.pool(), move |conn| {
       CommentReportQueryBuilder::create(conn)
@@ -173,59 +84,42 @@ impl Perform for GetReportCount {
     })
     .await??;
 
-    let response = GetReportCountResponse {
+    let res = GetReportCountResponse {
       community: community_id,
       comment_reports,
       post_reports,
     };
 
-    Ok(response)
+    context.chat_server().do_send(SendUserRoomMessage {
+      op: UserOperation::ListReports,
+      response: res.clone(),
+      recipient_id: user.id,
+      websocket_id,
+    });
+
+    Ok(res)
   }
 }
 
 #[async_trait::async_trait(?Send)]
-impl Perform for ListCommentReports {
-  type Response = ListCommentReportResponse;
+impl Perform for ListReports {
+  type Response = ListReportsResponse;
 
   async fn perform(
     &self,
     context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
-  ) -> Result<ListCommentReportResponse, LemmyError> {
-    let data: &ListCommentReports = &self;
+    websocket_id: Option<ConnectionId>,
+  ) -> Result<ListReportsResponse, LemmyError> {
+    let data: &ListReports = &self;
     let user = get_user_from_jwt(&data.auth, context.pool()).await?;
-
     let community_id = data.community;
-    //Check community exists.
-    let community_id = blocking(context.pool(), move |conn| {
-      CommunityView::read(conn, community_id, None)
-    })
-    .await??
-    .id;
-
-    check_community_ban(user.id, data.community, context.pool()).await?;
-
-    let mut mod_ids: Vec<i32> = Vec::new();
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        CommunityModeratorView::for_community(conn, community_id)
-          .map(|v| v.into_iter().map(|m| m.user_id).collect())
-      })
-      .await??,
-    );
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())
-      })
-      .await??,
-    );
-    if !mod_ids.contains(&user.id) {
-      return Err(APIError::err("report_view_not_allowed").into());
-    }
+
+    // Check for mod/admin privileges
+    is_mod_or_admin(context.pool(), user.id, community_id).await?;
 
     let page = data.page;
     let limit = data.limit;
-    let reports = blocking(context.pool(), move |conn| {
+    let comments = blocking(context.pool(), move |conn| {
       CommentReportQueryBuilder::create(conn)
         .community_id(community_id)
         .page(page)
@@ -234,161 +128,173 @@ impl Perform for ListCommentReports {
     })
     .await??;
 
-    Ok(ListCommentReportResponse { reports })
-  }
-}
-
-#[async_trait::async_trait(?Send)]
-impl Perform for ListPostReports {
-  type Response = ListPostReportResponse;
-
-  async fn perform(
-    &self,
-    context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
-  ) -> Result<ListPostReportResponse, LemmyError> {
-    let data: &ListPostReports = &self;
-    let user = get_user_from_jwt(&data.auth, context.pool()).await?;
-
-    let community_id = data.community;
-    //Check community exists.
-    let community_id = blocking(context.pool(), move |conn| {
-      CommunityView::read(conn, community_id, None)
-    })
-    .await??
-    .id;
-    // Check for community ban
-    check_community_ban(user.id, data.community, context.pool()).await?;
-
-    let mut mod_ids: Vec<i32> = Vec::new();
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        CommunityModeratorView::for_community(conn, community_id)
-          .map(|v| v.into_iter().map(|m| m.user_id).collect())
-      })
-      .await??,
-    );
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())
-      })
-      .await??,
-    );
-    if !mod_ids.contains(&user.id) {
-      return Err(APIError::err("report_view_not_allowed").into());
-    }
-
-    let page = data.page;
-    let limit = data.limit;
-    let reports = blocking(context.pool(), move |conn| {
+    let posts = blocking(context.pool(), move |conn| {
       PostReportQueryBuilder::create(conn)
-        .community_id(community_id)
-        .page(page)
-        .limit(limit)
-        .list()
+          .community_id(community_id)
+          .page(page)
+          .limit(limit)
+          .list()
     })
-    .await??;
+        .await??;
+
+    let res = ListReportsResponse { comments, posts };
 
-    Ok(ListPostReportResponse { reports })
+    context.chat_server().do_send(SendUserRoomMessage {
+      op: UserOperation::ListReports,
+      response: res.clone(),
+      recipient_id: user.id,
+      websocket_id,
+    });
+
+    Ok(res)
   }
 }
 
 #[async_trait::async_trait(?Send)]
-impl Perform for ResolveCommentReport {
-  type Response = ResolveCommentReportResponse;
+impl Perform for ResolveReport {
+  type Response = ResolveReportResponse;
 
   async fn perform(
     &self,
     context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
-  ) -> Result<ResolveCommentReportResponse, LemmyError> {
-    let data: &ResolveCommentReport = &self;
+    websocket_id: Option<ConnectionId>,
+  ) -> Result<ResolveReportResponse, LemmyError> {
+    let data: &ResolveReport = &self;
     let user = get_user_from_jwt(&data.auth, context.pool()).await?;
 
-    // Fetch the report view
-    let report_id = data.report;
-    let report = blocking(context.pool(), move |conn| CommentReportView::read(&conn, &report_id)).await??;
-
-    // Check for community ban
-    check_community_ban(user.id, report.community_id, context.pool()).await?;
-
-    // Check for mod/admin privileges
-    let mut mod_ids: Vec<i32> = Vec::new();
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        CommunityModeratorView::for_community(conn, report.community_id)
-          .map(|v| v.into_iter().map(|m| m.user_id).collect())
-      })
-      .await??,
-    );
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())
-      })
-      .await??,
-    );
-    if !mod_ids.contains(&user.id) {
-      return Err(APIError::err("resolve_report_not_allowed").into());
+    let report_type = ReportType::from_str(&data.report_type)?;
+    let user_id = user.id;
+    match report_type {
+      ReportType::Comment => { resolve_comment_report(context, data, user_id).await?; }
+      ReportType::Post => { resolve_post_report(context, data, user_id).await?; }
     }
 
-    blocking(context.pool(), move |conn| {
-      CommentReport::resolve(conn, &report_id.clone())
-    })
-    .await??;
-
-    Ok(ResolveCommentReportResponse {
-      report: report_id,
+    let report_id = data.report_id;
+    let res = ResolveReportResponse {
+      report_type: data.report_type.to_owned(),
+      report_id,
       resolved: true,
-    })
+    };
+
+    context.chat_server().do_send(SendUserRoomMessage {
+      op: UserOperation::ResolveReport,
+      response: res.clone(),
+      recipient_id: user.id,
+      websocket_id,
+    });
+
+    Ok(res)
   }
 }
 
-#[async_trait::async_trait(?Send)]
-impl Perform for ResolvePostReport {
-  type Response = ResolvePostReportResponse;
+async fn create_comment_report(
+  context: &Data<LemmyContext>,
+  data: &CreateReport,
+  user_id: i32,
+) -> Result<(), LemmyError> {
+  let comment_id = data.entity_id;
+  let comment = blocking(context.pool(), move |conn| {
+    CommentView::read(&conn, comment_id, None)
+  }).await??;
+
+  check_community_ban(user_id, comment.community_id, context.pool()).await?;
+
+  let report_form = CommentReportForm {
+    creator_id: user_id,
+    comment_id,
+    comment_text: comment.content,
+    reason: data.reason.to_owned(),
+  };
+
+  return match blocking(context.pool(), move |conn| {
+    CommentReport::report(conn, &report_form)
+  }).await? {
+    Ok(_) => Ok(()),
+    Err(_e) => Err(APIError::err("couldnt_create_report").into())
+  };
+}
 
-  async fn perform(
-    &self,
-    context: &Data<LemmyContext>,
-    _websocket_id: Option<ConnectionId>,
-  ) -> Result<ResolvePostReportResponse, LemmyError> {
-    let data: &ResolvePostReport = &self;
-    let user = get_user_from_jwt(&data.auth, context.pool()).await?;
+async fn create_post_report(
+  context: &Data<LemmyContext>,
+  data: &CreateReport,
+  user_id: i32,
+) -> Result<(), LemmyError> {
+  let post_id = data.entity_id;
+  let post = blocking(context.pool(), move |conn| {
+    PostView::read(&conn, post_id, None)
+  }).await??;
+
+  check_community_ban(user_id, post.community_id, context.pool()).await?;
+
+  let report_form = PostReportForm {
+    creator_id: user_id,
+    post_id,
+    post_name: post.name,
+    post_url: post.url,
+    post_body: post.body,
+    reason: data.reason.to_owned(),
+  };
+
+  return match blocking(context.pool(), move |conn| {
+    PostReport::report(conn, &report_form)
+  }).await? {
+    Ok(_) => Ok(()),
+    Err(_e) => Err(APIError::err("couldnt_create_report").into())
+  };
+}
 
-    // Fetch the report view
-    let report_id = data.report;
-    let report = blocking(context.pool(), move |conn| PostReportView::read(&conn, &report_id)).await??;
+async fn resolve_comment_report(
+  context: &Data<LemmyContext>,
+  data: &ResolveReport,
+  user_id: i32,
+) -> Result<(), LemmyError> {
+  let report_id = data.report_id;
+  let report = blocking(context.pool(), move |conn| {
+    CommentReportView::read(&conn, report_id)
+  }).await??;
+
+  is_mod_or_admin(context.pool(), user_id, report.community_id).await?;
+
+  let resolved = data.resolved;
+  let resolve_fun = move |conn: &'_ _| {
+    if resolved {
+      CommentReport::resolve(conn, report_id.clone(), user_id)
+    } else {
+      CommentReport::unresolve(conn, report_id.clone())
+    }
+  };
 
-    // Check for community ban
-    check_community_ban(user.id, report.community_id, context.pool()).await?;
+  if blocking(context.pool(),resolve_fun).await?.is_err() {
+    return Err(APIError::err("couldnt_resolve_report").into())
+  };
 
-    // Check for mod/admin privileges
-    let mut mod_ids: Vec<i32> = Vec::new();
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        CommunityModeratorView::for_community(conn, report.community_id)
-          .map(|v| v.into_iter().map(|m| m.user_id).collect())
-      })
-      .await??,
-    );
-    mod_ids.append(
-      &mut blocking(context.pool(), move |conn| {
-        UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())
-      })
-      .await??,
-    );
-    if !mod_ids.contains(&user.id) {
-      return Err(APIError::err("resolve_report_not_allowed").into());
+  Ok(())
+}
+
+async fn resolve_post_report(
+  context: &Data<LemmyContext>,
+  data: &ResolveReport,
+  user_id: i32,
+) -> Result<(), LemmyError> {
+  let report_id = data.report_id;
+  let report = blocking(context.pool(), move |conn| {
+    PostReportView::read(&conn, report_id)
+  }).await??;
+
+  is_mod_or_admin(context.pool(), user_id, report.community_id).await?;
+
+  let resolved = data.resolved;
+  let resolve_fun = move |conn: &'_ _| {
+    if resolved {
+      PostReport::resolve(conn, report_id.clone(), user_id)
+    } else {
+      PostReport::unresolve(conn, report_id.clone())
     }
+  };
 
-    blocking(context.pool(), move |conn| {
-      PostReport::resolve(conn, &report_id.clone())
-    })
-    .await??;
+  if blocking(context.pool(),resolve_fun).await?.is_err() {
+    return Err(APIError::err("couldnt_resolve_report").into())
+  };
 
-    Ok(ResolvePostReportResponse {
-      report: report_id,
-      resolved: true,
-    })
-  }
+  Ok(())
 }
index 2a358a3e126ba7f486bb0dd3139692f65f0633b1..904b16937ec2becd67de6e3d7a1cc68c12156fba 100644 (file)
@@ -9,7 +9,7 @@ path = "src/lib.rs"
 
 [dependencies]
 lemmy_utils = { path = "../lemmy_utils" }
-diesel = { version = "1.4", features = ["postgres","chrono","r2d2","64-column-tables","serde_json", "uuid"] }
+diesel = { version = "1.4", features = ["postgres","chrono","r2d2","64-column-tables","serde_json"] }
 chrono = { version = "0.4", features = ["serde"] }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", features = ["preserve_order"]}
@@ -21,4 +21,3 @@ bcrypt = "0.8"
 url = { version = "2.1", features = ["serde"] }
 lazy_static = "1.3"
 regex = "1.3"
-uuid = { version = "0.6.5", features = ["serde", "v4"] }
index 74d05e8c6e41a67d6a055f51dbf525d5761041c3..0725256c2d60952d922e6a2ff0d5c5e2748cae15 100644 (file)
@@ -1,31 +1,24 @@
-use diesel::{PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods, insert_into, update};
-use diesel::pg::Pg;
-use diesel::result::*;
+use diesel::{dsl::*, pg::Pg, result::Error, *};
 use serde::{Deserialize, Serialize};
 
-use crate::{
-  limit_and_offset,
-  MaybeOptional,
-  schema::comment_report,
-  comment::Comment,
-  Reportable,
-};
+use crate::{limit_and_offset, MaybeOptional, schema::comment_report, comment::Comment, Reportable, naive_now};
 
 table! {
     comment_report_view (id) {
-      id -> Uuid,
-      time -> Timestamp,
-      reason -> Nullable<Text>,
-      resolved -> Bool,
-      user_id -> Int4,
+      id -> Int4,
+      creator_id -> Int4,
       comment_id -> Int4,
       comment_text -> Text,
-      comment_time -> Timestamp,
+      reason -> Text,
+      resolved -> Bool,
+      resolver_id -> Nullable<Int4>,
+      published -> Timestamp,
+      updated -> Nullable<Timestamp>,
       post_id -> Int4,
       community_id -> Int4,
-      user_name -> Varchar,
-      creator_id -> Int4,
       creator_name -> Varchar,
+      comment_creator_id -> Int4,
+      comment_creator_name -> Varchar,
     }
 }
 
@@ -33,26 +26,24 @@ table! {
 #[belongs_to(Comment)]
 #[table_name = "comment_report"]
 pub struct CommentReport {
-  pub id: uuid::Uuid,
-  pub time: chrono::NaiveDateTime,
-  pub reason: Option<String>,
-  pub resolved: bool,
-  pub user_id: i32,
+  pub id: i32,
+  pub creator_id: i32,
   pub comment_id: i32,
   pub comment_text: String,
-  pub comment_time: chrono::NaiveDateTime,
+  pub reason: String,
+  pub resolved: bool,
+  pub resolver_id: Option<i32>,
+  pub published: chrono::NaiveDateTime,
+  pub updated: Option<chrono::NaiveDateTime>,
 }
 
 #[derive(Insertable, AsChangeset, Clone)]
 #[table_name = "comment_report"]
 pub struct CommentReportForm {
-  pub time: Option<chrono::NaiveDateTime>,
-  pub reason: Option<String>,
-  pub resolved: Option<bool>,
-  pub user_id: i32,
+  pub creator_id: i32,
   pub comment_id: i32,
   pub comment_text: String,
-  pub comment_time: chrono::NaiveDateTime,
+  pub reason: String,
 }
 
 impl Reportable<CommentReportForm> for CommentReport {
@@ -63,32 +54,47 @@ impl Reportable<CommentReportForm> for CommentReport {
         .get_result::<Self>(conn)
   }
 
-  fn resolve(conn: &PgConnection, report_id: &uuid::Uuid) -> Result<usize, Error> {
+  fn resolve(conn: &PgConnection, report_id: i32, by_user_id: i32) -> Result<usize, Error> {
     use crate::schema::comment_report::dsl::*;
     update(comment_report.find(report_id))
-        .set(resolved.eq(true))
+        .set((
+          resolved.eq(true),
+          resolver_id.eq(by_user_id),
+          updated.eq(naive_now()),
+        ))
+        .execute(conn)
+  }
+
+  fn unresolve(conn: &PgConnection, report_id: i32) -> Result<usize, Error> {
+    use crate::schema::comment_report::dsl::*;
+    update(comment_report.find(report_id))
+        .set((
+          resolved.eq(false),
+          updated.eq(naive_now()),
+        ))
         .execute(conn)
   }
 }
 
 #[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
+  Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
 )]
 #[table_name = "comment_report_view"]
 pub struct CommentReportView {
-  pub id: uuid::Uuid,
-  pub time: chrono::NaiveDateTime,
-  pub reason: Option<String>,
-  pub resolved: bool,
-  pub user_id: i32,
+  pub id: i32,
+  pub creator_id: i32,
   pub comment_id: i32,
   pub comment_text: String,
-  pub comment_time: chrono::NaiveDateTime,
+  pub reason: String,
+  pub resolved: bool,
+  pub resolver_id: Option<i32>,
+  pub published: chrono::NaiveDateTime,
+  pub updated: Option<chrono::NaiveDateTime>,
   pub post_id: i32,
   pub community_id: i32,
-  pub user_name: String,
-  pub creator_id: i32,
   pub creator_name: String,
+  pub comment_creator_id: i32,
+  pub comment_creator_name: String,
 }
 
 pub struct CommentReportQueryBuilder<'a> {
@@ -101,7 +107,7 @@ pub struct CommentReportQueryBuilder<'a> {
 }
 
 impl CommentReportView {
-  pub fn read(conn: &PgConnection, report_id: &uuid::Uuid) -> Result<Self, Error> {
+  pub fn read(conn: &PgConnection, report_id: i32) -> Result<Self, Error> {
     use super::comment_report::comment_report_view::dsl::*;
     comment_report_view
       .filter(id.eq(report_id))
@@ -161,7 +167,7 @@ impl<'a> CommentReportQueryBuilder<'a> {
     let (limit, offset) = limit_and_offset(self.page, self.limit);
 
     query
-      .order_by(time.desc())
+      .order_by(published.desc())
       .limit(limit)
       .offset(offset)
       .load::<CommentReportView>(self.conn)
index cf0e68ade48e887dec8ef2934b29413b619ce0a0..9e317f735563796cbdd93f7e65a2d2af4b1299ea 100644 (file)
@@ -115,7 +115,10 @@ pub trait Reportable<T> {
   fn report(conn: &PgConnection, form: &T) -> Result<Self, Error>
     where
         Self: Sized;
-  fn resolve(conn: &PgConnection, report_id: &uuid::Uuid) -> Result<usize, Error>
+  fn resolve(conn: &PgConnection, report_id: i32, user_id: i32) -> Result<usize, Error>
+    where
+        Self: Sized;
+  fn unresolve(conn: &PgConnection, report_id: i32) -> Result<usize, Error>
     where
         Self: Sized;
 }
@@ -170,6 +173,12 @@ pub enum SearchType {
   Url,
 }
 
+#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
+pub enum ReportType {
+  Comment,
+  Post,
+}
+
 pub fn fuzzy_search(q: &str) -> String {
   let replaced = q.replace(" ", "%");
   format!("%{}%", replaced)
index 4cb5e57011bdcd73b12f421bcc1d59614deecb6f..d461797c170e07bce9437ba78cafb5fe4270b6b8 100644 (file)
@@ -1,32 +1,25 @@
-use diesel::{PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods, insert_into, update};
-use diesel::pg::Pg;
-use diesel::result::*;
+use diesel::{dsl::*, pg::Pg, result::Error, *};
 use serde::{Deserialize, Serialize};
 
-use crate::{
-    limit_and_offset,
-    MaybeOptional,
-    schema::post_report,
-    post::Post,
-    Reportable,
-};
+use crate::{limit_and_offset, MaybeOptional, schema::post_report, post::Post, Reportable, naive_now};
 
 table! {
     post_report_view (id) {
-      id -> Uuid,
-      time -> Timestamp,
-      reason -> Nullable<Text>,
-      resolved -> Bool,
-      user_id -> Int4,
-      post_id -> Int4,
-      post_name -> Varchar,
-      post_url -> Nullable<Text>,
-      post_body -> Nullable<Text>,
-      post_time -> Timestamp,
-      community_id -> Int4,
-      user_name -> Varchar,
-      creator_id -> Int4,
-      creator_name -> Varchar,
+        id -> Int4,
+        creator_id -> Int4,
+        post_id -> Int4,
+        post_name -> Varchar,
+        post_url -> Nullable<Text>,
+        post_body -> Nullable<Text>,
+        reason -> Text,
+        resolved -> Bool,
+        resolver_id -> Nullable<Int4>,
+        published -> Timestamp,
+        updated -> Nullable<Timestamp>,
+        community_id -> Int4,
+        creator_name -> Varchar,
+        post_creator_id -> Int4,
+        post_creator_name -> Varchar,
     }
 }
 
@@ -34,30 +27,28 @@ table! {
 #[belongs_to(Post)]
 #[table_name = "post_report"]
 pub struct PostReport {
-    pub id: uuid::Uuid,
-    pub time: chrono::NaiveDateTime,
-    pub reason: Option<String>,
-    pub resolved: bool,
-    pub user_id: i32,
+    pub id: i32,
+    pub creator_id: i32,
     pub post_id: i32,
     pub post_name: String,
     pub post_url: Option<String>,
     pub post_body: Option<String>,
-    pub post_time: chrono::NaiveDateTime,
+    pub reason: String,
+    pub resolved: bool,
+    pub resolver_id: Option<i32>,
+    pub published: chrono::NaiveDateTime,
+    pub updated: Option<chrono::NaiveDateTime>,
 }
 
 #[derive(Insertable, AsChangeset, Clone)]
 #[table_name = "post_report"]
 pub struct PostReportForm {
-    pub time: Option<chrono::NaiveDateTime>,
-    pub reason: Option<String>,
-    pub resolved: Option<bool>,
-    pub user_id: i32,
+    pub creator_id: i32,
     pub post_id: i32,
     pub post_name: String,
     pub post_url: Option<String>,
     pub post_body: Option<String>,
-    pub post_time: chrono::NaiveDateTime,
+    pub reason: String,
 }
 
 impl Reportable<PostReportForm> for PostReport {
@@ -68,37 +59,52 @@ impl Reportable<PostReportForm> for PostReport {
             .get_result::<Self>(conn)
     }
 
-    fn resolve(conn: &PgConnection, report_id: &uuid::Uuid) -> Result<usize, Error> {
+    fn resolve(conn: &PgConnection, report_id: i32, by_user_id: i32) -> Result<usize, Error> {
         use crate::schema::post_report::dsl::*;
         update(post_report.find(report_id))
-            .set(resolved.eq(true))
+            .set((
+                resolved.eq(true),
+                resolver_id.eq(by_user_id),
+                updated.eq(naive_now()),
+            ))
+            .execute(conn)
+    }
+
+    fn unresolve(conn: &PgConnection, report_id: i32) -> Result<usize, Error> {
+        use crate::schema::post_report::dsl::*;
+        update(post_report.find(report_id))
+            .set((
+                resolved.eq(false),
+                updated.eq(naive_now()),
+            ))
             .execute(conn)
     }
 }
 
 #[derive(
-Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
+Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
 )]
 #[table_name = "post_report_view"]
 pub struct PostReportView {
-    pub id: uuid::Uuid,
-    pub time: chrono::NaiveDateTime,
-    pub reason: Option<String>,
-    pub resolved: bool,
-    pub user_id: i32,
+    pub id: i32,
+    pub creator_id: i32,
     pub post_id: i32,
     pub post_name: String,
     pub post_url: Option<String>,
     pub post_body: Option<String>,
-    pub post_time: chrono::NaiveDateTime,
+    pub reason: String,
+    pub resolved: bool,
+    pub resolver_id: Option<i32>,
+    pub published: chrono::NaiveDateTime,
+    pub updated: Option<chrono::NaiveDateTime>,
     pub community_id: i32,
-    pub user_name: String,
-    pub creator_id: i32,
     pub creator_name: String,
+    pub post_creator_id: i32,
+    pub post_creator_name: String,
 }
 
 impl PostReportView {
-    pub fn read(conn: &PgConnection, report_id: &uuid::Uuid) -> Result<Self, Error> {
+    pub fn read(conn: &PgConnection, report_id: i32) -> Result<Self, Error> {
         use super::post_report::post_report_view::dsl::*;
         post_report_view
             .filter(id.eq(report_id))
@@ -167,7 +173,7 @@ impl<'a> PostReportQueryBuilder<'a> {
         let (limit, offset) = limit_and_offset(self.page, self.limit);
 
         query
-            .order_by(time.desc())
+            .order_by(published.desc())
             .limit(limit)
             .offset(offset)
             .load::<PostReportView>(self.conn)
index 71034b7ada5a2709d0a11f330790c7423fc1902a..494c1ec877d9ec18343da725c3ecddee691aab87 100644 (file)
@@ -83,14 +83,15 @@ table! {
 
 table! {
     comment_report (id) {
-        id -> Uuid,
-        time -> Timestamp,
-        reason -> Nullable<Text>,
-        resolved -> Bool,
-        user_id -> Int4,
+        id -> Int4,
+        creator_id -> Int4,
         comment_id -> Int4,
         comment_text -> Text,
-        comment_time -> Timestamp,
+        reason -> Text,
+        resolved -> Bool,
+        resolver_id -> Nullable<Int4>,
+        published -> Timestamp,
+        updated -> Nullable<Timestamp>,
     }
 }
 
@@ -385,16 +386,17 @@ table! {
 
 table! {
     post_report (id) {
-        id -> Uuid,
-        time -> Timestamp,
-        reason -> Nullable<Text>,
-        resolved -> Bool,
-        user_id -> Int4,
+        id -> Int4,
+        creator_id -> Int4,
         post_id -> Int4,
         post_name -> Varchar,
         post_url -> Nullable<Text>,
         post_body -> Nullable<Text>,
-        post_time -> Timestamp,
+        reason -> Text,
+        resolved -> Bool,
+        resolver_id -> Nullable<Int4>,
+        published -> Timestamp,
+        updated -> Nullable<Timestamp>,
     }
 }
 
@@ -516,7 +518,6 @@ joinable!(comment_like -> comment (comment_id));
 joinable!(comment_like -> post (post_id));
 joinable!(comment_like -> user_ (user_id));
 joinable!(comment_report -> comment (comment_id));
-joinable!(comment_report -> user_ (user_id));
 joinable!(comment_saved -> comment (comment_id));
 joinable!(comment_saved -> user_ (user_id));
 joinable!(community -> category (category_id));
@@ -547,7 +548,6 @@ joinable!(post_like -> user_ (user_id));
 joinable!(post_read -> post (post_id));
 joinable!(post_read -> user_ (user_id));
 joinable!(post_report -> post (post_id));
-joinable!(post_report -> user_ (user_id));
 joinable!(post_saved -> post (post_id));
 joinable!(post_saved -> user_ (user_id));
 joinable!(site -> user_ (creator_id));
@@ -556,38 +556,38 @@ joinable!(user_mention -> comment (comment_id));
 joinable!(user_mention -> user_ (recipient_id));
 
 allow_tables_to_appear_in_same_query!(
-  activity,
-  category,
-  comment,
-  comment_aggregates_fast,
-  comment_like,
-  comment_report,
-  comment_saved,
-  community,
-  community_aggregates_fast,
-  community_follower,
-  community_moderator,
-  community_user_ban,
-  mod_add,
-  mod_add_community,
-  mod_ban,
-  mod_ban_from_community,
-  mod_lock_post,
-  mod_remove_comment,
-  mod_remove_community,
-  mod_remove_post,
-  mod_sticky_post,
-  password_reset_request,
-  post,
-  post_aggregates_fast,
-  post_like,
-  post_read,
-  post_report,
-  post_saved,
-  private_message,
-  site,
-  user_,
-  user_ban,
-  user_fast,
-  user_mention,
+    activity,
+    category,
+    comment,
+    comment_aggregates_fast,
+    comment_like,
+    comment_report,
+    comment_saved,
+    community,
+    community_aggregates_fast,
+    community_follower,
+    community_moderator,
+    community_user_ban,
+    mod_add,
+    mod_add_community,
+    mod_ban,
+    mod_ban_from_community,
+    mod_lock_post,
+    mod_remove_comment,
+    mod_remove_community,
+    mod_remove_post,
+    mod_sticky_post,
+    password_reset_request,
+    post,
+    post_aggregates_fast,
+    post_like,
+    post_read,
+    post_report,
+    post_saved,
+    private_message,
+    site,
+    user_,
+    user_ban,
+    user_fast,
+    user_mention,
 );
index 22fad79e9cc67435220d2779ce6592168d49ae0d..303181e9be503b0f23bf6729ef52fa820857f8b4 100644 (file)
@@ -16,5 +16,4 @@ log = "0.4"
 diesel = "1.4"
 actix-web = { version = "3.0" }
 chrono = { version = "0.4", features = ["serde"] }
-serde_json = { version = "1.0", features = ["preserve_order"]}
-uuid = { version = "0.6.5", features = ["serde", "v4"] }
\ No newline at end of file
+serde_json = { version = "1.0", features = ["preserve_order"]}
\ No newline at end of file
index ed12e2614140b8c007d348c0aa362f514abd89d2..842bfcaaaf2bef9c8dc3010c5cf621ab64fa8ef9 100644 (file)
@@ -1,57 +1,31 @@
-use lemmy_db::{
-    comment_report::CommentReportView,
-    post_report::PostReportView,
-};
+use lemmy_db::{comment_report::CommentReportView, post_report::PostReportView};
 use serde::{Deserialize, Serialize};
 
 #[derive(Serialize, Deserialize)]
-pub struct CreateCommentReport {
-    pub comment: i32,
-    pub reason: Option<String>,
+pub struct CreateReport {
+    pub report_type: String,
+    pub entity_id: i32,
+    pub reason: String,
     pub auth: String,
 }
 
 #[derive(Serialize, Deserialize, Clone)]
-pub struct CommentReportResponse {
+pub struct CreateReportResponse {
     pub success: bool,
 }
 
-#[derive(Serialize, Deserialize)]
-pub struct CreatePostReport {
-    pub post: i32,
-    pub reason: Option<String>,
-    pub auth: String,
-}
-
-#[derive(Serialize, Deserialize, Clone)]
-pub struct PostReportResponse {
-    pub success: bool,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct ListCommentReports {
-    pub page: Option<i64>,
-    pub limit: Option<i64>,
-    pub community: i32,
-    pub auth: String,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct ListCommentReportResponse {
-    pub reports: Vec<CommentReportView>,
-}
-
 #[derive(Serialize, Deserialize, Debug)]
-pub struct ListPostReports {
+pub struct ListReports {
     pub page: Option<i64>,
     pub limit: Option<i64>,
     pub community: i32,
     pub auth: String,
 }
 
-#[derive(Serialize, Deserialize, Debug)]
-pub struct ListPostReportResponse {
-    pub reports: Vec<PostReportView>,
+#[derive(Serialize, Deserialize, Clone, Debug)]
+pub struct ListReportsResponse {
+    pub posts: Vec<PostReportView>,
+    pub comments: Vec<CommentReportView>,
 }
 
 #[derive(Serialize, Deserialize, Debug)]
@@ -60,7 +34,7 @@ pub struct GetReportCount {
     pub auth: String,
 }
 
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug)]
 pub struct GetReportCountResponse {
     pub community: i32,
     pub comment_reports: usize,
@@ -68,25 +42,16 @@ pub struct GetReportCountResponse {
 }
 
 #[derive(Serialize, Deserialize, Debug)]
-pub struct ResolveCommentReport {
-    pub report: uuid::Uuid,
-    pub auth: String,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct ResolveCommentReportResponse {
-    pub report: uuid::Uuid,
+pub struct ResolveReport {
+    pub report_type: String,
+    pub report_id: i32,
     pub resolved: bool,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct ResolvePostReport {
-    pub report: uuid::Uuid,
     pub auth: String,
 }
 
-#[derive(Serialize, Deserialize, Debug)]
-pub struct ResolvePostReportResponse {
-    pub report: uuid::Uuid,
+#[derive(Serialize, Deserialize, Clone, Debug)]
+pub struct ResolveReportResponse {
+    pub report_type: String,
+    pub report_id: i32,
     pub resolved: bool,
 }
index d5e056dcf765c9b4790ccbd895187156b95a31cf..30c95d6ad9a31dcd841083607d7445af23357676 100644 (file)
@@ -97,9 +97,6 @@ pub enum UserOperation {
   MarkCommentAsRead,
   SaveComment,
   CreateCommentLike,
-  CreateCommentReport,
-  ListCommentReports,
-  ResolveCommentReport,
   GetPosts,
   CreatePostLike,
   EditPost,
@@ -108,9 +105,10 @@ pub enum UserOperation {
   LockPost,
   StickyPost,
   SavePost,
-  CreatePostReport,
-  ListPostReports,
-  ResolvePostReport,
+  CreateReport,
+  ResolveReport,
+  ListReports,
+  GetReportCount,
   EditCommunity,
   DeleteCommunity,
   RemoveCommunity,
@@ -121,7 +119,6 @@ pub enum UserOperation {
   GetUserMentions,
   MarkUserMentionAsRead,
   GetModlog,
-  GetReportCount,
   BanFromCommunity,
   AddModToCommunity,
   CreateSite,
index 436f6dd4d00cbd4b0a382aef8e3593334edf1677..e1c39faaf2b4eeb1f23cacac3cd6d3f47adb5fa0 100644 (file)
@@ -2,4 +2,3 @@ drop view comment_report_view;
 drop view post_report_view;
 drop table comment_report;
 drop table post_report;
-drop extension "uuid-ossp";
index 7f6f554272183b1cf42216b7b990578bcbce9057..98553625da53069abbbc035587e1105295aa5445 100644 (file)
@@ -1,51 +1,51 @@
-create extension "uuid-ossp";
-
 create table comment_report (
-  id            uuid      primary key default uuid_generate_v4(),
-  time          timestamp not null default now(),
-  reason        text,
-  resolved      bool      not null default false,
-  user_id       int       references user_ on update cascade on delete cascade not null,   -- user reporting comment
+  id            serial    primary key,
+  creator_id    int       references user_ on update cascade on delete cascade not null,   -- user reporting comment
   comment_id    int       references comment on update cascade on delete cascade not null, -- comment being reported
   comment_text  text      not null,
-  comment_time  timestamp not null,
-  unique(comment_id, user_id) -- users should only be able to report a comment once
+  reason        text      not null,
+  resolved      bool      not null default false,
+  resolver_id   int       references user_ on update cascade on delete cascade not null,   -- user resolving report
+  published     timestamp not null default now(),
+  updated       timestamp null,
+  unique(comment_id, creator_id) -- users should only be able to report a comment once
 );
 
 create table post_report (
-  id            uuid      primary key default uuid_generate_v4(),
-  time          timestamp not null default now(),
-  reason        text,
-  resolved      bool      not null default false,
-  user_id       int       references user_ on update cascade on delete cascade not null, -- user reporting post
+  id            serial    primary key,
+  creator_id    int       references user_ on update cascade on delete cascade not null, -- user reporting post
   post_id       int       references post on update cascade on delete cascade not null,  -- post being reported
-  post_name    varchar(100) not null,
+  post_name        varchar(100) not null,
   post_url      text,
   post_body     text,
-  post_time     timestamp not null,
-  unique(post_id, user_id) -- users should only be able to report a post once
+  reason        text      not null,
+  resolved      bool      not null default false,
+  resolver_id   int       references user_ on update cascade on delete cascade not null,   -- user resolving report
+  published     timestamp not null default now(),
+  updated       timestamp null,
+  unique(post_id, creator_id) -- users should only be able to report a post once
 );
 
 create or replace view comment_report_view as
 select cr.*,
 c.post_id,
 p.community_id,
-f.name as user_name,
-u.id as creator_id,
-u.name as creator_name
+f.name as creator_name,
+u.id as comment_creator_id,
+u.name as comment_creator_name
 from comment_report cr
 left join comment c on c.id = cr.comment_id
 left join post p on p.id = c.post_id
 left join user_ u on u.id = c.creator_id
-left join user_ f on f.id = cr.user_id;
+left join user_ f on f.id = cr.creator_id;
 
 create or replace view post_report_view as
 select pr.*,
 p.community_id,
-f.name as user_name,
-u.id as creator_id,
-u.name as creator_name
+f.name as creator_name,
+u.id as post_creator_id,
+u.name as post_creator_name
 from post_report pr
 left join post p on p.id = pr.post_id
 left join user_ u on u.id = p.creator_id
-left join user_ f on f.id = pr.user_id;
+left join user_ f on f.id = pr.creator_id;
index 9cbca652728193185ca245d731ef149f83a72199..6563b2305c7f05340577c0c410748c72f29ef2ec 100644 (file)
@@ -58,9 +58,6 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
           .route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
           .route("/mod", web::post().to(route_post::<AddModToCommunity>))
           .route("/join", web::post().to(route_post::<CommunityJoin>))
-          .route("/comment_reports",web::get().to(route_get::<ListCommentReports>))
-          .route("/post_reports", web::get().to(route_get::<ListPostReports>))
-          .route("/reports", web::get().to(route_get::<GetReportCount>)),
       )
       // Post
       .service(
@@ -83,12 +80,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
           .route("/like", web::post().to(route_post::<CreatePostLike>))
           .route("/save", web::put().to(route_post::<SavePost>))
           .route("/join", web::post().to(route_post::<PostJoin>))
-          .route("/report", web::put().to(route_post::<CreatePostReport>))
-          .route("/resolve_report",web::post().to(route_post::<ResolvePostReport>)),
       )
       // Comment
       .service(
-        web::scope("/comment")
+          web::scope("/comment")
           .wrap(rate_limit.message())
           .route("", web::post().to(route_post::<CreateComment>))
           .route("", web::put().to(route_post::<EditComment>))
@@ -101,8 +96,6 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
           .route("/like", web::post().to(route_post::<CreateCommentLike>))
           .route("/save", web::put().to(route_post::<SaveComment>))
           .route("/list", web::get().to(route_get::<GetComments>))
-          .route("/report", web::put().to(route_post::<CreateCommentReport>))
-          .route("/resolve_report",web::post().to(route_post::<ResolveCommentReport>)),
       )
       // Private Message
       .service(
@@ -177,6 +170,15 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
         web::resource("/admin/add")
           .wrap(rate_limit.message())
           .route(web::post().to(route_post::<AddAdmin>)),
+      )
+      // Reports
+      .service(
+        web::scope("/report")
+            .wrap(rate_limit.message())
+            .route("", web::get().to(route_get::<GetReportCount>))
+            .route("",web::post().to(route_post::<CreateReport>))
+            .route("/resolve",web::put().to(route_post::<ResolveReport>))
+            .route("/list", web::get().to(route_get::<ListReports>))
       ),
   );
 }