Adding post_id and type_ filters to combined reports. (#5348)

* Adding post_id and type_ filters to combined reports.

- Added tests for these also.
- Some additional cleanup of the joins in reports_combined.
- Fixes #5265

* Adding period.
This commit is contained in:
Dessalines 2025-01-27 04:13:45 -05:00 committed by GitHub
parent 8ee81a3967
commit 012e8c3085
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 116 additions and 55 deletions

View file

@ -15,9 +15,6 @@ pub async fn list_reports(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<ListReportsResponse>> {
let community_id = data.community_id;
let unresolved_only = data.unresolved_only;
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
// parse pagination token
@ -29,8 +26,10 @@ pub async fn list_reports(
let page_back = data.page_back;
let reports = ReportCombinedQuery {
community_id,
unresolved_only,
community_id: data.community_id,
post_id: data.post_id,
type_: data.type_,
unresolved_only: data.unresolved_only,
page_after,
page_back,
}

View file

@ -35,7 +35,7 @@ use std::{cmp::min, time::Duration};
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Saves settings for your user.
/// A response that completes successfully.
pub struct SuccessResponse {
pub success: bool,
}

View file

@ -1,4 +1,7 @@
use lemmy_db_schema::newtypes::CommunityId;
use lemmy_db_schema::{
newtypes::{CommunityId, PostId},
ReportType,
};
use lemmy_db_views::structs::{ReportCombinedPaginationCursor, ReportCombinedView};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
@ -14,6 +17,12 @@ pub struct ListReports {
/// Only shows the unresolved reports
#[cfg_attr(feature = "full", ts(optional))]
pub unresolved_only: Option<bool>,
/// Filter the type of report.
#[cfg_attr(feature = "full", ts(optional))]
pub type_: Option<ReportType>,
/// Filter by the post id. Can return either comment or post reports.
#[cfg_attr(feature = "full", ts(optional))]
pub post_id: Option<PostId>,
/// if no community is given, it returns reports for all communities moderated by the auth user
#[cfg_attr(feature = "full", ts(optional))]
pub community_id: Option<CommunityId>,

View file

@ -229,13 +229,25 @@ pub enum InboxDataType {
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// A list of possible types for the various modlog actions.
/// A list of possible types for a person's content.
pub enum PersonContentType {
All,
Comments,
Posts,
}
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// A list of possible types for reports.
pub enum ReportType {
All,
Posts,
Comments,
PrivateMessages,
Communities,
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash,
)]

View file

@ -22,7 +22,7 @@ use diesel_async::RunQueryDsl;
use i_love_jesus::PaginatedQueryBuilder;
use lemmy_db_schema::{
aliases::{self, creator_community_actions},
newtypes::CommunityId,
newtypes::{CommunityId, PostId},
schema::{
comment,
comment_actions,
@ -49,6 +49,7 @@ use lemmy_db_schema::{
},
traits::InternalToCombinedView,
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool, ReverseTimestampKey},
ReportType,
};
use lemmy_utils::error::LemmyResult;
@ -148,6 +149,8 @@ pub struct PaginationCursorData(ReportCombined);
#[derive(Default)]
pub struct ReportCombinedQuery {
pub type_: Option<ReportType>,
pub post_id: Option<PostId>,
pub community_id: Option<CommunityId>,
pub unresolved_only: Option<bool>,
pub page_after: Option<PaginationCursorData>,
@ -167,6 +170,33 @@ impl ReportCombinedQuery {
let conn = &mut get_conn(pool).await?;
let report_creator_join = post_report::creator_id
.eq(report_creator)
.or(comment_report::creator_id.eq(report_creator))
.or(private_message_report::creator_id.eq(report_creator))
.or(community_report::creator_id.eq(report_creator));
let item_creator_join = post::creator_id
.eq(item_creator)
.or(comment::creator_id.eq(item_creator))
.or(private_message::creator_id.eq(item_creator));
let resolver_join = private_message_report::resolver_id
.eq(resolver)
.or(post_report::resolver_id.eq(resolver))
.or(comment_report::resolver_id.eq(resolver))
.or(community_report::resolver_id.eq(resolver));
let post_join = post_report::post_id
.eq(post::id)
.or(comment::post_id.eq(post::id));
let community_join = community::table.on(
community_report::community_id
.eq(community::id)
.or(post::community_id.eq(community::id)),
);
// Notes: since the post_report_id and comment_report_id are optional columns,
// many joins must use an OR condition.
// For example, the report creator must be the person table joined to either:
@ -178,15 +208,7 @@ impl ReportCombinedQuery {
.left_join(private_message_report::table)
.left_join(community_report::table)
// The report creator
.inner_join(
person::table.on(
post_report::creator_id
.eq(report_creator)
.or(comment_report::creator_id.eq(report_creator))
.or(private_message_report::creator_id.eq(report_creator))
.or(community_report::creator_id.eq(report_creator)),
),
)
.inner_join(person::table.on(report_creator_join))
// The comment
.left_join(comment::table.on(comment_report::comment_id.eq(comment::id)))
// The private message
@ -195,30 +217,13 @@ impl ReportCombinedQuery {
.on(private_message_report::private_message_id.eq(private_message::id)),
)
// The post
.left_join(
post::table.on(
post_report::post_id
.eq(post::id)
.or(comment::post_id.eq(post::id)),
),
)
.left_join(post::table.on(post_join))
// The item creator (`item_creator` is the id of this person)
.left_join(
aliases::person1.on(
post::creator_id
.eq(item_creator)
.or(comment::creator_id.eq(item_creator))
.or(private_message::creator_id.eq(item_creator)),
),
)
.left_join(aliases::person1.on(item_creator_join))
// The resolver
.left_join(aliases::person2.on(resolver_join))
// The community
.left_join(
community::table.on(
post::community_id
.eq(community::id)
.or(community_report::community_id.eq(community::id)),
),
)
.left_join(community_join)
.left_join(actions_alias(
creator_community_actions,
item_creator,
@ -250,16 +255,6 @@ impl ReportCombinedQuery {
community_aggregates::table
.on(community_report::community_id.eq(community_aggregates::community_id)),
)
// The resolver
.left_join(
aliases::person2.on(
private_message_report::resolver_id
.eq(resolver)
.or(post_report::resolver_id.eq(resolver))
.or(comment_report::resolver_id.eq(resolver))
.or(community_report::resolver_id.eq(resolver)),
),
)
.left_join(actions(
comment_actions::table,
Some(my_person_id),
@ -318,6 +313,10 @@ impl ReportCombinedQuery {
);
}
if let Some(post_id) = self.post_id {
query = query.filter(post::id.eq(post_id));
}
// If its not an admin, get only the ones you mod
if !user.local_user.admin {
query = query.filter(
@ -337,6 +336,18 @@ impl ReportCombinedQuery {
query = query.after(page_after);
}
if let Some(type_) = self.type_ {
query = match type_ {
ReportType::All => query,
ReportType::Posts => query.filter(report_combined::post_report_id.is_not_null()),
ReportType::Comments => query.filter(report_combined::comment_report_id.is_not_null()),
ReportType::PrivateMessages => {
query.filter(report_combined::private_message_report_id.is_not_null())
}
ReportType::Communities => query.filter(report_combined::community_report_id.is_not_null()),
}
}
// If viewing all reports, order by newest, but if viewing unresolved only, show the oldest
// first (FIFO)
if self.unresolved_only.unwrap_or_default() {
@ -508,6 +519,7 @@ mod tests {
},
traits::{Crud, Joinable, Reportable},
utils::{build_db_pool_for_tests, DbPool},
ReportType,
};
use lemmy_utils::error::LemmyResult;
use pretty_assertions::assert_eq;
@ -677,7 +689,7 @@ mod tests {
let reports = ReportCombinedQuery::default()
.list(pool, &data.admin_view)
.await?;
assert_eq!(4, reports.len());
assert_length!(4, reports);
// Make sure the report types are correct
if let ReportCombinedView::Community(v) = &reports[3] {
@ -709,22 +721,41 @@ mod tests {
ReportCombinedViewInternal::get_report_count(pool, &data.admin_view, None).await?;
assert_eq!(4, report_count_admin);
// Make sure the type_ filter is working
let reports_by_type = ReportCombinedQuery {
type_: Some(ReportType::Posts),
..Default::default()
}
.list(pool, &data.admin_view)
.await?;
assert_length!(1, reports_by_type);
// Filter by the post id
// Should be 2, for the post, and the comment on that post
let reports_by_post_id = ReportCombinedQuery {
post_id: Some(data.post.id),
..Default::default()
}
.list(pool, &data.admin_view)
.await?;
assert_length!(2, reports_by_post_id);
// Timmy should only see 2 reports, since they're not an admin,
// but they do mod the community
let reports = ReportCombinedQuery::default()
let timmys_reports = ReportCombinedQuery::default()
.list(pool, &data.timmy_view)
.await?;
assert_eq!(2, reports.len());
assert_length!(2, timmys_reports);
// Make sure the report types are correct
if let ReportCombinedView::Post(v) = &reports[1] {
if let ReportCombinedView::Post(v) = &timmys_reports[1] {
assert_eq!(data.post.id, v.post.id);
assert_eq!(data.sara.id, v.creator.id);
assert_eq!(data.timmy.id, v.post_creator.id);
} else {
panic!("wrong type");
}
if let ReportCombinedView::Comment(v) = &reports[0] {
if let ReportCombinedView::Comment(v) = &timmys_reports[0] {
assert_eq!(data.comment.id, v.comment.id);
assert_eq!(data.post.id, v.post.id);
assert_eq!(data.timmy.id, v.comment_creator.id);
@ -1050,6 +1081,16 @@ mod tests {
ReportCombinedViewInternal::get_report_count(pool, &data.timmy_view, None).await?;
assert_eq!(1, report_count_after_resolved);
// Filter by post id, which should still include the comments.
let reports_post_id_filter = ReportCombinedQuery {
post_id: Some(data.post.id),
..Default::default()
}
.list(pool, &data.timmy_view)
.await?;
assert_length!(2, reports_post_id_filter);
cleanup(data, pool).await?;
Ok(())