diff --git a/app/models/topic.rb b/app/models/topic.rb index 19a3da5902e..4e160b6b3a4 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -231,10 +231,19 @@ class Topic < ActiveRecord::Base posts.order('score desc').limit(1).first end + def has_flags? + FlagQuery.flagged_post_actions("active") + .where("topics.id" => id) + .exists? + end + # all users (in groups or directly targetted) that are going to get the pm def all_allowed_users - # TODO we should probably change this from 3 queries to 1 - User.where('id in (?)', allowed_users.select('users.id').to_a + allowed_group_users.select('users.id').to_a) + # TODO we should probably change this to 1 query + allowed_user_ids = allowed_users.select('users.id').to_a + allowed_group_user_ids = allowed_group_users.select('users.id').to_a + allowed_staff_ids = private_message? && has_flags? ? User.where(moderator: true).pluck(:id).to_a : [] + User.where('id IN (?)', allowed_user_ids + allowed_group_user_ids + allowed_staff_ids) end # Additional rate limits on topics: per day and private messages per day diff --git a/lib/flag_query.rb b/lib/flag_query.rb index 2fe90c1c195..aed258c8274 100644 --- a/lib/flag_query.rb +++ b/lib/flag_query.rb @@ -6,7 +6,9 @@ module FlagQuery guardian = Guardian.new(current_user) if !guardian.is_admin? - actions = actions.where('category_id in (?)', guardian.allowed_category_ids) + actions = actions.where('category_id IN (:allowed_category_ids) OR archetype = :private_message', + allowed_category_ids: guardian.allowed_category_ids, + private_message: Archetype.private_message) end post_ids = actions.limit(per_page) @@ -107,26 +109,24 @@ module FlagQuery ] end - protected - - def self.flagged_post_actions(filter) - post_actions = PostAction.flags - .joins("INNER JOIN posts ON posts.id = post_actions.post_id") - .joins("INNER JOIN topics ON topics.id = posts.topic_id") - .joins("LEFT JOIN users ON users.id = posts.user_id") - - if filter == "old" - post_actions.where("post_actions.disagreed_at IS NOT NULL OR - post_actions.deferred_at IS NOT NULL OR - post_actions.agreed_at IS NOT NULL") - else - post_actions.active - .where("posts.deleted_at" => nil) - .where("topics.deleted_at" => nil) - end + def self.flagged_post_actions(filter) + post_actions = PostAction.flags + .joins("INNER JOIN posts ON posts.id = post_actions.post_id") + .joins("INNER JOIN topics ON topics.id = posts.topic_id") + .joins("LEFT JOIN users ON users.id = posts.user_id") + if filter == "old" + post_actions.where("post_actions.disagreed_at IS NOT NULL OR + post_actions.deferred_at IS NOT NULL OR + post_actions.agreed_at IS NOT NULL") + else + post_actions.active + .where("posts.deleted_at" => nil) + .where("topics.deleted_at" => nil) end + end + private def self.excerpt(cooked) diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb index 2a6318ab9d8..e39f46b838f 100644 --- a/spec/components/guardian_spec.rb +++ b/spec/components/guardian_spec.rb @@ -381,6 +381,19 @@ describe Guardian do expect(Guardian.new(moderator).can_edit?(tos_topic)).to be_falsey expect(Guardian.new(admin).can_edit?(tos_topic)).to be_truthy end + + it "allows moderators to see a flagged private message" do + moderator.save! + user.save! + + private_topic = Fabricate(:private_message_topic, user: user) + first_post = Fabricate(:post, topic: private_topic, user: user) + + expect(Guardian.new(moderator).can_see?(private_topic)).to be_falsey + + PostAction.act(user, first_post, PostActionType.types[:off_topic]) + expect(Guardian.new(moderator).can_see?(private_topic)).to be_truthy + end end describe 'a Post' do