Adding listing_type filter for modlog. (#5399)

* Adding listing_type filter for modlog.

- Fixes #4219

* Running fmt.

* Change the listing_type.all to not filter by community.

* Adding GetModlog API docs.

* Addressing PR comments 2
This commit is contained in:
Dessalines 2025-02-07 12:53:15 -05:00 committed by GitHub
parent 496ae58cb6
commit d8a4fd6125
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 160 additions and 111 deletions

View file

@ -18,10 +18,11 @@ pub async fn get_mod_log(
check_private_instance(&local_user_view, &local_site)?;
let type_ = data.type_;
let listing_type = data.listing_type;
let community_id = data.community_id;
let is_mod_or_admin = if let Some(local_user_view) = local_user_view {
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool())
let is_mod_or_admin = if let Some(local_user_view) = &local_user_view {
check_community_mod_of_any_or_admin_action(local_user_view, &mut context.pool())
.await
.is_ok()
} else {
@ -37,6 +38,7 @@ pub async fn get_mod_log(
let other_person_id = data.other_person_id;
let post_id = data.post_id;
let comment_id = data.comment_id;
let local_user = local_user_view.as_ref().map(|u| &u.local_user);
// parse pagination token
let page_after = if let Some(pa) = &data.page_cursor {
@ -48,9 +50,11 @@ pub async fn get_mod_log(
let modlog = ModlogCombinedQuery {
type_,
listing_type,
community_id,
mod_person_id,
other_person_id,
local_user,
post_id,
comment_id,
hide_modlog_names: Some(hide_modlog_names),

View file

@ -124,16 +124,26 @@ pub struct ResolveObjectResponse {
#[cfg_attr(feature = "full", ts(export))]
/// Fetches the modlog.
pub struct GetModlog {
/// Filter by the moderator.
#[cfg_attr(feature = "full", ts(optional))]
pub mod_person_id: Option<PersonId>,
/// Filter by the community.
#[cfg_attr(feature = "full", ts(optional))]
pub community_id: Option<CommunityId>,
/// Filter by the modlog action type.
#[cfg_attr(feature = "full", ts(optional))]
pub type_: Option<ModlogActionType>,
/// Filter by listing type. When not using All, it will remove the non-community modlog entries,
/// such as site bans, instance blocks, adding an admin, etc.
#[cfg_attr(feature = "full", ts(optional))]
pub listing_type: Option<ListingType>,
/// Filter by the other / modded person.
#[cfg_attr(feature = "full", ts(optional))]
pub other_person_id: Option<PersonId>,
/// Filter by post. Will include comments of that post.
#[cfg_attr(feature = "full", ts(optional))]
pub post_id: Option<PostId>,
/// Filter by comment.
#[cfg_attr(feature = "full", ts(optional))]
pub comment_id: Option<CommentId>,
#[cfg_attr(feature = "full", ts(optional))]

View file

@ -34,6 +34,7 @@ use diesel_async::RunQueryDsl;
use i_love_jesus::PaginatedQueryBuilder;
use lemmy_db_schema::{
aliases,
impls::local_user::LocalUserOptionHelper,
newtypes::{CommentId, CommunityId, PersonId, PostId},
schema::{
admin_allow_instance,
@ -44,6 +45,7 @@ use lemmy_db_schema::{
admin_purge_post,
comment,
community,
community_actions,
instance,
mod_add,
mod_add_community,
@ -60,15 +62,23 @@ use lemmy_db_schema::{
person,
post,
},
source::combined::modlog::{modlog_combined_keys as key, ModlogCombined},
source::{
combined::modlog::{modlog_combined_keys as key, ModlogCombined},
local_user::LocalUser,
},
traits::InternalToCombinedView,
utils::{get_conn, DbPool},
ListingType,
ModlogActionType,
};
use lemmy_utils::error::LemmyResult;
impl ModlogCombinedViewInternal {
#[diesel::dsl::auto_type(no_type_alias)]
fn joins(mod_person_id: Option<PersonId>, hide_modlog_names: Option<bool>) -> _ {
fn joins(
mod_person_id: Option<PersonId>,
hide_modlog_names: Option<bool>,
my_person_id: Option<PersonId>,
) -> _ {
// The modded / other person
let other_person = aliases::person1.field(person::id);
@ -78,101 +88,117 @@ impl ModlogCombinedViewInternal {
// The query for the admin / mod person
// It needs an OR condition to every mod table
// After this you can use person::id to refer to the moderator
let moderator_names_join = show_mod_names_expr
.or(person::id.nullable().eq(mod_person_id))
.and(
admin_allow_instance::admin_person_id
.eq(person::id)
.or(admin_block_instance::admin_person_id.eq(person::id))
.or(admin_purge_comment::admin_person_id.eq(person::id))
.or(admin_purge_community::admin_person_id.eq(person::id))
.or(admin_purge_person::admin_person_id.eq(person::id))
.or(admin_purge_post::admin_person_id.eq(person::id))
.or(mod_add::mod_person_id.eq(person::id))
.or(mod_add_community::mod_person_id.eq(person::id))
.or(mod_ban::mod_person_id.eq(person::id))
.or(mod_ban_from_community::mod_person_id.eq(person::id))
.or(mod_feature_post::mod_person_id.eq(person::id))
.or(mod_hide_community::mod_person_id.eq(person::id))
.or(mod_lock_post::mod_person_id.eq(person::id))
.or(mod_remove_comment::mod_person_id.eq(person::id))
.or(mod_remove_community::mod_person_id.eq(person::id))
.or(mod_remove_post::mod_person_id.eq(person::id))
.or(mod_transfer_community::mod_person_id.eq(person::id)),
);
let moderator_names_join = person::table.on(
show_mod_names_expr
.or(person::id.nullable().eq(mod_person_id))
.and(
admin_allow_instance::admin_person_id
.eq(person::id)
.or(admin_block_instance::admin_person_id.eq(person::id))
.or(admin_purge_comment::admin_person_id.eq(person::id))
.or(admin_purge_community::admin_person_id.eq(person::id))
.or(admin_purge_person::admin_person_id.eq(person::id))
.or(admin_purge_post::admin_person_id.eq(person::id))
.or(mod_add::mod_person_id.eq(person::id))
.or(mod_add_community::mod_person_id.eq(person::id))
.or(mod_ban::mod_person_id.eq(person::id))
.or(mod_ban_from_community::mod_person_id.eq(person::id))
.or(mod_feature_post::mod_person_id.eq(person::id))
.or(mod_hide_community::mod_person_id.eq(person::id))
.or(mod_lock_post::mod_person_id.eq(person::id))
.or(mod_remove_comment::mod_person_id.eq(person::id))
.or(mod_remove_community::mod_person_id.eq(person::id))
.or(mod_remove_post::mod_person_id.eq(person::id))
.or(mod_transfer_community::mod_person_id.eq(person::id)),
),
);
let other_person_join = mod_add::other_person_id
.eq(other_person)
.or(mod_add_community::other_person_id.eq(other_person))
.or(mod_ban::other_person_id.eq(other_person))
.or(mod_ban_from_community::other_person_id.eq(other_person))
// Some tables don't have the other_person_id directly, so you need to join
.or(
mod_feature_post::id
.is_not_null()
.and(post::creator_id.eq(other_person)),
)
.or(
mod_lock_post::id
.is_not_null()
.and(post::creator_id.eq(other_person)),
)
.or(
mod_remove_comment::id
.is_not_null()
.and(comment::creator_id.eq(other_person)),
)
.or(
mod_remove_post::id
.is_not_null()
.and(post::creator_id.eq(other_person)),
)
.or(mod_transfer_community::other_person_id.eq(other_person));
let other_person_join = aliases::person1.on(
mod_add::other_person_id
.eq(other_person)
.or(mod_add_community::other_person_id.eq(other_person))
.or(mod_ban::other_person_id.eq(other_person))
.or(mod_ban_from_community::other_person_id.eq(other_person))
// Some tables don't have the other_person_id directly, so you need to join
.or(
mod_feature_post::id
.is_not_null()
.and(post::creator_id.eq(other_person)),
)
.or(
mod_lock_post::id
.is_not_null()
.and(post::creator_id.eq(other_person)),
)
.or(
mod_remove_comment::id
.is_not_null()
.and(comment::creator_id.eq(other_person)),
)
.or(
mod_remove_post::id
.is_not_null()
.and(post::creator_id.eq(other_person)),
)
.or(mod_transfer_community::other_person_id.eq(other_person)),
);
let comment_join = mod_remove_comment::comment_id.eq(comment::id);
let comment_join = comment::table.on(mod_remove_comment::comment_id.eq(comment::id));
let post_join = admin_purge_comment::post_id
.eq(post::id)
.or(mod_feature_post::post_id.eq(post::id))
.or(mod_lock_post::post_id.eq(post::id))
.or(
mod_remove_comment::id
.is_not_null()
.and(comment::post_id.eq(post::id)),
)
.or(mod_remove_post::post_id.eq(post::id));
let post_join = post::table.on(
admin_purge_comment::post_id
.eq(post::id)
.or(mod_feature_post::post_id.eq(post::id))
.or(mod_lock_post::post_id.eq(post::id))
.or(
mod_remove_comment::id
.is_not_null()
.and(comment::post_id.eq(post::id)),
)
.or(mod_remove_post::post_id.eq(post::id)),
);
let community_join = admin_purge_post::community_id
.eq(community::id)
.or(mod_add_community::community_id.eq(community::id))
.or(mod_ban_from_community::community_id.eq(community::id))
.or(
mod_feature_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_hide_community::community_id.eq(community::id))
.or(
mod_lock_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(
mod_remove_comment::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_remove_community::community_id.eq(community::id))
.or(
mod_remove_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_transfer_community::community_id.eq(community::id));
let community_join = community::table.on(
admin_purge_post::community_id
.eq(community::id)
.or(mod_add_community::community_id.eq(community::id))
.or(mod_ban_from_community::community_id.eq(community::id))
.or(
mod_feature_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_hide_community::community_id.eq(community::id))
.or(
mod_lock_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(
mod_remove_comment::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_remove_community::community_id.eq(community::id))
.or(
mod_remove_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_transfer_community::community_id.eq(community::id)),
);
let instance_join = admin_allow_instance::instance_id
.eq(instance::id)
.or(admin_block_instance::instance_id.eq(instance::id));
let instance_join = instance::table.on(
admin_allow_instance::instance_id
.eq(instance::id)
.or(admin_block_instance::instance_id.eq(instance::id)),
);
let community_actions_join = community_actions::table.on(
community_actions::community_id
.eq(community::id)
.and(community_actions::person_id.nullable().eq(my_person_id)),
);
modlog_combined::table
.left_join(admin_allow_instance::table)
@ -192,18 +218,13 @@ impl ModlogCombinedViewInternal {
.left_join(mod_remove_community::table)
.left_join(mod_remove_post::table)
.left_join(mod_transfer_community::table)
// The moderator
.left_join(person::table.on(moderator_names_join))
// The comment
.left_join(comment::table.on(comment_join))
// The post
.left_join(post::table.on(post_join))
// The community
.left_join(community::table.on(community_join))
// The instance
.left_join(instance::table.on(instance_join))
// The other / modded person
.left_join(aliases::person1.on(other_person_join))
.left_join(moderator_names_join)
.left_join(comment_join)
.left_join(post_join)
.left_join(community_join)
.left_join(instance_join)
.left_join(other_person_join)
.left_join(community_actions_join)
}
}
@ -284,26 +305,30 @@ pub struct PaginationCursorData(ModlogCombined);
#[derive(Default)]
/// Querying / filtering the modlog.
pub struct ModlogCombinedQuery {
pub struct ModlogCombinedQuery<'a> {
pub type_: Option<ModlogActionType>,
pub listing_type: Option<ListingType>,
pub comment_id: Option<CommentId>,
pub post_id: Option<PostId>,
pub community_id: Option<CommunityId>,
pub hide_modlog_names: Option<bool>,
pub local_user: Option<&'a LocalUser>,
pub mod_person_id: Option<PersonId>,
pub other_person_id: Option<PersonId>,
pub page_after: Option<PaginationCursorData>,
pub page_back: Option<bool>,
}
impl ModlogCombinedQuery {
impl ModlogCombinedQuery<'_> {
pub async fn list(self, pool: &mut DbPool<'_>) -> LemmyResult<Vec<ModlogCombinedView>> {
let conn = &mut get_conn(pool).await?;
let other_person = aliases::person1.field(person::id);
let my_person_id = self.local_user.person_id();
let mut query = ModlogCombinedViewInternal::joins(self.mod_person_id, self.hide_modlog_names)
.select(ModlogCombinedViewInternal::as_select())
.into_boxed();
let mut query =
ModlogCombinedViewInternal::joins(self.mod_person_id, self.hide_modlog_names, my_person_id)
.select(ModlogCombinedViewInternal::as_select())
.into_boxed();
if let Some(mod_person_id) = self.mod_person_id {
query = query.filter(person::id.eq(mod_person_id));
@ -355,6 +380,16 @@ impl ModlogCombinedQuery {
}
}
let is_subscribed = community_actions::followed.is_not_null();
query = match self.listing_type.unwrap_or(ListingType::All) {
ListingType::All => query,
ListingType::Subscribed => query.filter(is_subscribed),
ListingType::Local => query
.filter(community::local.eq(true))
.filter(community::hidden.eq(false).or(is_subscribed)),
ListingType::ModeratorView => query.filter(community_actions::became_moderator.is_not_null()),
};
let mut query = PaginatedQueryBuilder::new(query);
let page_after = self.page_after.map(|c| c.0);