FIX: Exclude deleted posts and topics from assignments lists in various places (#34564)

This PR adds a check if the post an assignment is attached to is deleted
(by the author or another user) prior to listing it in
`/topics/group-topics-assigned/group_name.json`. This is done via
TopicQuery

Related:
https://meta.discourse.org/t/topic-deletion-should-clear-assignment/271996
This commit is contained in:
Natalie Tay
2025-08-27 17:01:38 +08:00
committed by GitHub
parent 0d4ca82c91
commit 5de7572434
2 changed files with 57 additions and 10 deletions
+16 -10
View File
@@ -376,18 +376,24 @@ after_initialize do
add_to_class(:topic_query, :group_topics_assigned_results) do |group|
list = default_results(include_all_pms: true)
topic_ids_sql = +<<~SQL
SELECT topic_id FROM assignments
WHERE (
assigned_to_id = :group_id AND assigned_to_type = 'Group' AND active
)
SQL
assignee_condition = "(a.assigned_to_id = :group_id AND a.assigned_to_type = 'Group')"
if @options[:filter] != :direct
assignee_condition +=
" OR (a.assigned_to_id IN (SELECT user_id from group_users where group_id = :group_id) AND a.assigned_to_type = 'User')"
end
topic_ids_sql << <<~SQL if @options[:filter] != :direct
OR (
assigned_to_id IN (SELECT user_id from group_users where group_id = :group_id) AND assigned_to_type = 'User' AND active
topic_ids_sql = <<~SQL
SELECT a.topic_id FROM assignments a
LEFT JOIN topics t ON t.id = a.topic_id
LEFT JOIN posts p ON p.id = a.target_id AND a.target_type = 'Post'
WHERE a.active
AND t.deleted_at IS NULL
AND (
a.target_type = 'Topic' OR
(a.target_type = 'Post' AND p.deleted_at IS NULL AND p.deleted_by_id IS NULL AND p.user_deleted = false)
)
SQL
AND (#{assignee_condition})
SQL
sql = "topics.id IN (#{topic_ids_sql})"
@@ -103,6 +103,47 @@ describe TopicQuery do
expect(assigned_messages).to contain_exactly(group_topic)
end
it "excludes assignments to deleted posts and topics" do
# Create a new topic with only a post assignment (no topic assignment)
post_only_topic = Fabricate(:post, user: user).topic
post_in_topic = Fabricate(:post, topic: post_only_topic)
assign_to(post_in_topic, user, user)
assigned_messages =
TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics
expect(assigned_messages).to contain_exactly(
private_message,
topic,
group_topic,
post_only_topic,
)
# delete entire topic (soft deletion)
post_only_topic.update!(deleted_at: Time.current)
assigned_messages =
TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics
expect(assigned_messages).to contain_exactly(private_message, topic, group_topic)
# restore topic, but delete the post (moderator deletion)
post_only_topic.update!(deleted_at: nil)
post_in_topic.update!(deleted_at: Time.current)
assigned_messages =
TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics
expect(assigned_messages).to contain_exactly(private_message, topic, group_topic)
# user deletion of post
post_in_topic.update!(deleted_at: nil, user_deleted: true)
assigned_messages =
TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics
expect(assigned_messages).to contain_exactly(private_message, topic, group_topic)
# system deletion of post
post_in_topic.update!(user_deleted: false, deleted_by_id: Discourse.system_user.id)
assigned_messages =
TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics
expect(assigned_messages).to contain_exactly(private_message, topic, group_topic)
end
end
describe "#list_private_messages_assigned" do