Repository: LemmyNet/lemmy (language: rust)

Issue:
Add the ability for users to view their sent reports
### Requirements

- [X] Is this a feature request? For questions or discussions use https://lemmy.ml/c/lemmy_support
- [X] Did you check to see if this issue already exists?
- [X] Is this only a feature request? Do not put multiple feature requests in one issue.
- [X] Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
- [X] Do you agree to follow the rules in our [Code of Conduct](https://join-lemmy.org/docs/code_of_conduct.html)?

### Is your proposal related to a problem?

I've often been messaged by admins or mods about reports I've made asking for more info on them, or accidentally sent an unfinished report on a comment or post, sometimes I've also sent reports on the wrong comment by mistake.

### Describe the solution you'd like.

I think users should have the ability to see their reports that they have sent, as well as the ability to delete or dismiss them as necessary. That way if their report is referenced by a mod they can go back and look at what it says, or if they sent it on the wrong comment or didn't finish it, they can go back and either delete it or dismiss it.

### Describe alternatives you've considered.

Could just allow people to view the reports they've sent out for future context, wouldn't be as useful as being able to edit and delete them as well but if it's too challenging to implement report editing in a way that is Activitypub compliant this is the better option.

### Additional context

_No response_


Discussion / hints:
This could probably be abused, #5110 seems like a better solution.
Viewing should be possible, possibly deleting.
Editing should probably be limited to append-only.

At least viewing seems entirely reasonable, even if nothing else gets implemented for now.
> This could probably be abused, #5110 seems like a better solution.

If abuse is a concern it could be limited to viewing only, possibly deleting. #5110 doesn't solve the issue of not remembering why you sent a report when questioned later, it's about offering a better way of contacting moderators.
Alright Im reopening and changing the title.
I like this, and I think we can leave it to just viewing the reports you sent for now. Otherwise it'd be a lot of apub work to send the edits and deletes, which might not be clean.
Please consider the delete report scheme, I just reported someone by sleeping on the phone (😭) and I can't delete, even as an admin of my own instance the only solution is mark it as resolved (which means ? is that basically a TODO ?)
> Please consider the delete report scheme, I just reported someone by sleeping on the phone (😭) and I can't delete, even as an admin of my own instance the only solution is mark it as resolved (which means ? is that basically a TODO ?)

Resolved means exactly what it says it means. It means the report is resolved and doesn't appear as a notification anymore. It'll still appear in the history but that's it.
That said @dessalines It might be a good idea to also have people be able to resolve their own reports. I know some admins can get pretty mad about accidental reports, so being able to resolve an oops before they get pissed off or give you a lecture would be pretty useful.

Fix patch:
diff --git a/crates/api/src/reports/report_combined/list.rs b/crates/api/src/reports/report_combined/list.rs
index d471bc016b..187c98e3bd 100644
--- a/crates/api/src/reports/report_combined/list.rs
+++ b/crates/api/src/reports/report_combined/list.rs
@@ -14,7 +14,12 @@ pub async fn list_reports(
   context: Data<LemmyContext>,
   local_user_view: LocalUserView,
 ) -> LemmyResult<Json<ListReportsResponse>> {
-  check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
+  let my_reports_only = data.my_reports_only;
+
+  // Only check mod or admin status when not viewing my reports
+  if !my_reports_only.unwrap_or_default() {
+    check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
+  }
 
   // parse pagination token
   let page_after = if let Some(pa) = &data.page_cursor {
@@ -32,6 +37,7 @@ pub async fn list_reports(
     page_after,
     page_back,
     show_community_rule_violations: data.show_community_rule_violations,
+    my_reports_only,
   }
   .list(&mut context.pool(), &local_user_view)
   .await?;
diff --git a/crates/api_common/src/reports/combined.rs b/crates/api_common/src/reports/combined.rs
index e527ff467c..2efbac1744 100644
--- a/crates/api_common/src/reports/combined.rs
+++ b/crates/api_common/src/reports/combined.rs
@@ -33,6 +33,9 @@ pub struct ListReports {
   /// Only for admins: also show reports with `violates_instance_rules=false`
   #[cfg_attr(feature = "full", ts(optional))]
   pub show_community_rule_violations: Option<bool>,
+  /// If true, view all your created reports. Works for non-admins/mods also.
+  #[cfg_attr(feature = "full", ts(optional))]
+  pub my_reports_only: Option<bool>,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
diff --git a/crates/db_views/src/combined/report_combined_view.rs b/crates/db_views/src/combined/report_combined_view.rs
index 2ecae6cb4f..5c023458fe 100644
--- a/crates/db_views/src/combined/report_combined_view.rs
+++ b/crates/db_views/src/combined/report_combined_view.rs
@@ -255,6 +255,7 @@ pub struct ReportCombinedQuery {
   pub unresolved_only: Option<bool>,
   /// For admins, also show reports with `violates_instance_rules=false`
   pub show_community_rule_violations: Option<bool>,
+  pub my_reports_only: Option<bool>,
   pub page_after: Option<PaginationCursorData>,
   pub page_back: Option<bool>,
 }
@@ -335,6 +336,10 @@ impl ReportCombinedQuery {
       query = query.filter(post::id.eq(post_id));
     }
 
+    if self.my_reports_only.unwrap_or_default() {
+      query = query.filter(person::id.eq(my_person_id));
+    }
+
     let mut query = PaginatedQueryBuilder::new(query);
 
     let page_after = self.page_after.map(|c| c.0);
@@ -674,7 +679,7 @@ mod tests {
 
   #[tokio::test]
   #[serial]
-  async fn test_combined() -> LemmyResult<()> {
+  async fn combined() -> LemmyResult<()> {
     let pool = &build_db_pool_for_tests();
     let pool = &mut pool.into();
     let data = init_data(pool).await?;
@@ -845,7 +850,7 @@ mod tests {
 
   #[tokio::test]
   #[serial]
-  async fn test_private_message_reports() -> LemmyResult<()> {
+  async fn private_message_reports() -> LemmyResult<()> {
     let pool = &build_db_pool_for_tests();
     let pool = &mut pool.into();
     let data = init_data(pool).await?;
@@ -909,7 +914,7 @@ mod tests {
 
   #[tokio::test]
   #[serial]
-  async fn test_post_reports() -> LemmyResult<()> {
+  async fn post_reports() -> LemmyResult<()> {
     let pool = &build_db_pool_for_tests();
     let pool = &mut pool.into();
     let data = init_data(pool).await?;
@@ -1042,7 +1047,7 @@ mod tests {
 
   #[tokio::test]
   #[serial]
-  async fn test_comment_reports() -> LemmyResult<()> {
+  async fn comment_reports() -> LemmyResult<()> {
     let pool = &build_db_pool_for_tests();
     let pool = &mut pool.into();
     let data = init_data(pool).await?;
@@ -1158,7 +1163,7 @@ mod tests {
 
   #[tokio::test]
   #[serial]
-  async fn test_community_reports() -> LemmyResult<()> {
+  async fn community_reports() -> LemmyResult<()> {
     let pool = &build_db_pool_for_tests();
     let pool = &mut pool.into();
     let data = init_data(pool).await?;
@@ -1222,7 +1227,7 @@ mod tests {
 
   #[tokio::test]
   #[serial]
-  async fn test_violates_instance_rules() -> LemmyResult<()> {
+  async fn violates_instance_rules() -> LemmyResult<()> {
     let pool = &build_db_pool_for_tests();
     let pool = &mut pool.into();
     let data = init_data(pool).await?;
@@ -1309,4 +1314,55 @@ mod tests {
 
     Ok(())
   }
+
+  #[tokio::test]
+  #[serial]
+  async fn my_reports_only() -> LemmyResult<()> {
+    let pool = &build_db_pool_for_tests();
+    let pool = &mut pool.into();
+    let data = init_data(pool).await?;
+
+    // sara reports
+    let sara_report_form = CommentReportForm {
+      creator_id: data.sara.id,
+      comment_id: data.comment.id,
+      original_comment_text: "this was it at time of creation".into(),
+      reason: "from sara".into(),
+      violates_instance_rules: false,
+    };
+    CommentReport::report(pool, &sara_report_form).await?;
+
+    // timmy reports
+    let timmy_report_form = CommentReportForm {
+      creator_id: data.timmy.id,
+      comment_id: data.comment.id,
+      original_comment_text: "this was it at time of creation".into(),
+      reason: "from timmy".into(),
+      violates_instance_rules: false,
+    };
+    CommentReport::report(pool, &timmy_report_form).await?;
+
+    let agg = CommentAggregates::read(pool, data.comment.id).await?;
+    assert_eq!(agg.report_count, 2);
+
+    // Do a batch read of timmys reports, it should only show his own
+    let reports = ReportCombinedQuery {
+      my_reports_only: Some(true),
+      ..Default::default()
+    }
+    .list(pool, &data.timmy_view)
+    .await?;
+
+    assert_length!(1, reports);
+
+    if let ReportCombinedView::Comment(v) = &reports[0] {
+      assert_eq!(v.creator.id, data.timmy.id);
+    } else {
+      panic!("wrong type");
+    }
+
+    cleanup(data, pool).await?;
+
+    Ok(())
+  }
 }


Test patch: