Skip to content

Add bulk bulk_action_parent_id field to modlog table#6352

Merged
dessalines merged 14 commits intoLemmyNet:mainfrom
EduardoLZevallos:add-bulk-field-to-modlog
Mar 3, 2026
Merged

Add bulk bulk_action_parent_id field to modlog table#6352
dessalines merged 14 commits intoLemmyNet:mainfrom
EduardoLZevallos:add-bulk-field-to-modlog

Conversation

@EduardoLZevallos
Copy link
Copy Markdown
Contributor

@EduardoLZevallos EduardoLZevallos commented Feb 21, 2026

This is for issue #6323

each bulk child entry now stores a foreign key back to the modlog row that triggered it

Closes LemmyNet#6323

Adds a new `bulk` boolean column to the modlog table so that bulk
actions (e.g. removing all content when banning a user) can be
distinguished from individual mod actions in the frontend.
@Nothing4You
Copy link
Copy Markdown
Collaborator

wouldn't it make more sense to store the parent id instead? non-bulk/parents could have this set to NULL, and for others it will then also allow determining the initial action that resulted in this.
clients could then also display all the actions that were triggered by the current action.

@EduardoLZevallos
Copy link
Copy Markdown
Contributor Author

wouldn't it make more sense to store the parent id instead? non-bulk/parents could have this set to NULL, and for others it will then also allow determining the initial action that resulted in this. clients could then also display all the actions that were triggered by the current action.

I think this makes sense. just to make sure I follow completely, for example

The ban entry is inserted into modlog first → gets id = 36 , parent_id = NULL (it's a root action, nobody triggered it)
Every post/comment removal that results from that ban is inserted with parent_id = 36

bulk actions are therefore anything where the parent_id is not null
actions that triggered the ban? search based on the parent_id
to determine the removal look for the row with id equal to the particular parent id

One thing is that I'll likely need to ensure this works on the federated path since parent_id requires the parent row to exist first.parent_id requires the parent row to exist first.

Thanks for the feedback @Nothing4You let me know if I'm understanding your feedback fully.

@Nutomic
Copy link
Copy Markdown
Member

Nutomic commented Feb 23, 2026

I agree that it makes sense to include the parent id, so they can be grouped together in the UI. To be more explicit I would call it bulk_action_parent_id. Your description how to implement this sounds reasonable.

It would also make sense to change ModlogView to hide bulk items by default, and then add a new api parameter bulk_action_id or similar, which returns all child actions corresponding to that one.

Copy link
Copy Markdown
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if it makes sense to include the parent_id, because we already have modlog filters for post_id, comment_id, community_id.

Because if we did add parent_id, I'd prefer that to reference which type of id it would be (IE parent_post_id, parent_community_id) , and that could get pretty complicated. The filters above should already work good enough, and having a simple is_bulk to GetModlog should be enough.

Another way to put it, is that the modlog table already stores things like target_post_id, target_community_id, etc. So adding another target_parent_id would be redundant.

ModlogView {
modlog: Modlog {
is_revert: true,
is_bulk: true,
Copy link
Copy Markdown
Member

@dessalines dessalines Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these should also be false.

.list(pool)
.await?
.items;
assert_eq!(1, modlog.len());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also be sure to add tests for when bulk removal is true.

@Nothing4You
Copy link
Copy Markdown
Collaborator

Another way to put it, is that the modlog table already stores things like target_post_id, target_community_id, etc. So adding another target_parent_id would be redundant.

It's not redundant to have data that clearly links the two actions.
If a user and their content get banned from a community, the post gets removed as bulk action.
If a user gets banned from the instance, the post gets removed as bulk action.
The modlog doesn't track whether a ban was with content removal, so it cannot be reliably determined which of the bans triggered the removal. At best, a client could try to correlate these actions based on the timestamp.

From UI/client perspective, I think the following would be useful:

  • instance modlog should only show non-bulk actions by default
  • community modlog should always show community bans and unbans by default, otherwise only non-bulk actions
  • being able to tell whether a modlog parent has any children, to avoid needlessly needing to query for children of all returned items individually

Additionally, having explicit modlog child records are useful when reversing a ban, by being able to selectively undo e.g. post/comment removals from a community ban. A moderator could click an undo button on a community ban modlog entry and this could restore all posts that were removed as part of the ban, without restoring posts that may have been removed for unrelated reasons.

@dessalines
Copy link
Copy Markdown
Member

dessalines commented Feb 23, 2026

If a user and their content get banned from a community, the post gets removed as bulk action.
If a user gets banned from the instance, the post gets removed as bulk action.

It does make sense to link them, but then we'll at least need bulk_parent_post_id, bulk_parent_community_id, bulk_parent_instance_id , to link the parent level it was bulk removed at. I think that's all of them.

community modlog should always show community bans and unbans by default, otherwise only non-bulk actions ...

I think in that case it makes sense to add the bulk_...id filters (instead of a simple bulk: boolean) to GetModlog, so that people can explicitly filter for the bulk actions at each of those levels. Front ends can use their own logic to determine which bulk ones they want.

@Nothing4You
Copy link
Copy Markdown
Collaborator

If a user and their content get banned from a community, the post gets removed as bulk action.
If a user gets banned from the instance, the post gets removed as bulk action.

It does make sense to link them, but then we'll at least need bulk_parent_post_id, bulk_parent_community_id, bulk_parent_instance_id , to link the parent level it was bulk removed at. I think that's all of them.

the parent would refer to another modlog entry. i'm not quite sure why we would need to split the references by type? a single modlog entry should only have a single parent, and they'd all refer to another row in the same table.

@EduardoLZevallos
Copy link
Copy Markdown
Contributor Author

If a user and their content get banned from a community, the post gets removed as bulk action.
If a user gets banned from the instance, the post gets removed as bulk action.

It does make sense to link them, but then we'll at least need bulk_parent_post_id, bulk_parent_community_id, bulk_parent_instance_id , to link the parent level it was bulk removed at. I think that's all of them.

the parent would refer to another modlog entry. i'm not quite sure why we would need to split the references by type? a single modlog entry should only have a single parent, and they'd all refer to another row in the same table.

"a single modlog entry should only have a single parent, and they'd all refer to another row in the same table." this makes the most sense to me. I want to confirm this is the approach we'd like to move forward with before implementing again.

I'll call it bulk_action_parent_id

@dessalines
Copy link
Copy Markdown
Member

dessalines commented Feb 24, 2026

That seems fine.

I think on the API side, we'll still just need a show_bulk: boolean anyway (in addition to bulk_parent_id), because someone looking at the modlog might just want a simple checkbox showing all the bulk operations, and not want to have to know parent ids before seeing all the entries.

Instead of a boolean flag, store a reference to the parent modlog entry
that triggered bulk content removal (e.g. the ban that caused all of a
user's posts to be removed). NULL means an individual action; non-null
means a bulk action triggered by the referenced entry.
@Nutomic
Copy link
Copy Markdown
Member

Nutomic commented Feb 25, 2026

You need to format the code with cargo +nightly fmt --all. And generally check the CI output to see whats missing (https://woodpecker.join-lemmy.org/repos/129/pipeline/19131/9). See .woodpecker.yml for the commands it runs.

@EduardoLZevallos
Copy link
Copy Markdown
Contributor Author

You need to format the code with cargo +nightly fmt --all. And generally check the CI output to see whats missing (https://woodpecker.join-lemmy.org/repos/129/pipeline/19131/9). See .woodpecker.yml for the commands it runs.

thanks . Will check through that now

ALTER TABLE modlog
ADD COLUMN bulk_action_parent_id int REFERENCES modlog (id) ON DELETE SET NULL;

CREATE INDEX idx_modlog_bulk_action_parent_id ON modlog (bulk_action_parent_id);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use where bulk_action_parent_id is not null to use less storage space.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think over time the majority of rows will probably have this set, so i don't think this will long term be saving a significant amount of space.
it would exclude the index from being usable for non-bulk queries. i'm not sure if would make a noticeable difference in practice. an index scan for published would happen first and then i'd expect a sequential scan to rule out rows that were retrieved from the published index but have the bulk column null. for large bulk operations this could result in hundreds to thousands of rows being read and skipped from the sequential scan.

it might make sense to generate some synthetic data and look at query plans.

@EduardoLZevallos
Copy link
Copy Markdown
Contributor Author

thanks for the feedback all. Will address it this weekend

  mod_remove_comment constructor functions
- Pass Some(id) at bulk call sites (utils.rs) and None at individual
  mod action sites (api_crud, apub deletion/undo_delete)
- Fix ModlogQuery to skip IS NULL guard when bulk_action_parent_id
  filter is provided (was making the eq filter unreachable)
eduardo added 2 commits March 1, 2026 18:48
…odlog

# Conflicts:
#	crates/api/api_crud/src/comment/remove.rs
#	crates/api/api_crud/src/post/remove.rs
#	crates/api/api_utils/src/utils.rs
#	crates/apub/activities/src/deletion/delete.rs
#	crates/apub/activities/src/deletion/undo_delete.rs
#	crates/db_views/modlog/src/impls.rs
#	crates/db_views/notification/src/tests.rs
@EduardoLZevallos EduardoLZevallos force-pushed the add-bulk-field-to-modlog branch from 09b8f09 to 5e4b075 Compare March 2, 2026 00:55
Copy link
Copy Markdown
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only 1 major thing having to do with bulk comment removals. Everything else is minor:

…lk_action_parent_id as well. Also moved parent_id into varsper pr feedback
@Nutomic Nutomic changed the title Add bulk boolean field to modlog table Add bulk bulk_action_parent_id field to modlog table Mar 3, 2026
Copy link
Copy Markdown
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent job, thx!

@dessalines dessalines merged commit 01e1f0e into LemmyNet:main Mar 3, 2026
2 checks passed
@EduardoLZevallos
Copy link
Copy Markdown
Contributor Author

Excellent job, thx!

sorry got busy with work. Thanks for all the feedback all! my first contribution to this project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants