2017-09-06 10:21:07 -04:00
require 'ostruct'
2013-08-19 21:14:26 +10:00
module FlagQuery
2017-09-08 16:47:49 -04:00
def self . flagged_posts_report ( current_user , opts = nil )
opts ||= {}
offset = opts [ :offset ] || 0
per_page = opts [ :per_page ] || 25
actions = flagged_post_actions ( opts )
2013-08-19 21:14:26 +10:00
2014-02-07 14:11:52 +11:00
guardian = Guardian . new ( current_user )
if ! guardian . is_admin?
2017-09-08 16:47:49 -04:00
actions = actions . where (
'category_id IN (:allowed_category_ids) OR archetype = :private_message' ,
2015-02-16 13:03:04 +01:00
allowed_category_ids : guardian . allowed_category_ids ,
2017-09-08 16:47:49 -04:00
private_message : Archetype . private_message
)
2014-02-07 14:11:52 +11:00
end
2017-09-12 13:04:53 -04:00
total_rows = actions . count
2018-05-07 15:14:18 -04:00
post_ids_relation = actions . limit ( per_page )
2017-07-28 10:20:09 +09:00
. offset ( offset )
. group ( :post_id )
. order ( 'MIN(post_actions.created_at) DESC' )
2018-05-07 15:14:18 -04:00
if opts [ :filter ] != "old" && SiteSetting . min_flags_staff_visibility > 1
post_ids_relation = post_ids_relation . having ( "count(*) >= ?" , SiteSetting . min_flags_staff_visibility )
end
post_ids = post_ids_relation . pluck ( :post_id ) . uniq
2013-08-19 21:14:26 +10:00
2014-07-28 19:17:37 +02:00
posts = SqlBuilder . new ( "
SELECT p.id,
p.cooked,
2018-01-30 16:31:29 -05:00
p.raw,
2014-07-28 19:17:37 +02:00
p.user_id,
p.topic_id,
p.post_number,
2018-04-04 18:16:44 +02:00
p.reply_count,
2014-07-28 19:17:37 +02:00
p.hidden,
2014-08-18 18:56:39 +02:00
p.deleted_at,
2014-09-09 20:26:40 +02:00
p.user_deleted,
2014-09-08 17:53:29 +02:00
(SELECT created_at FROM post_revisions WHERE post_id = p.id AND user_id = p.user_id ORDER BY created_at DESC LIMIT 1) AS last_revised_at,
(SELECT COUNT(*) FROM post_actions WHERE (disagreed_at IS NOT NULL OR agreed_at IS NOT NULL OR deferred_at IS NOT NULL) AND post_id = p.id)::int AS previous_flags_count
2014-07-28 19:17:37 +02:00
FROM posts p
WHERE p.id in (:post_ids)" ) . map_exec ( OpenStruct , post_ids : post_ids )
2013-08-19 21:14:26 +10:00
post_lookup = {}
2014-07-28 19:17:37 +02:00
user_ids = Set . new
topic_ids = Set . new
2013-08-19 21:14:26 +10:00
posts . each do | p |
2014-07-28 19:17:37 +02:00
user_ids << p . user_id
topic_ids << p . topic_id
2013-08-19 21:14:26 +10:00
p . excerpt = Post . excerpt ( p . cooked )
2014-07-28 19:17:37 +02:00
p . delete_field ( :cooked )
2013-08-19 21:14:26 +10:00
post_lookup [ p . id ] = p
end
2014-07-28 19:17:37 +02:00
post_actions = actions . order ( 'post_actions.created_at DESC' )
2017-07-28 10:20:09 +09:00
. includes ( related_post : { topic : { ordered_posts : :user } })
. where ( post_id : post_ids )
2013-08-19 21:14:26 +10:00
2017-09-11 16:44:20 -04:00
all_post_actions = []
2013-08-19 21:14:26 +10:00
post_actions . each do | pa |
post = post_lookup [ pa . post_id ]
2017-09-11 16:44:20 -04:00
if opts [ :rest_api ]
post . post_action_ids ||= []
else
post . post_actions ||= []
end
2014-07-28 19:17:37 +02:00
# TODO: add serializer so we can skip this
action = {
id : pa . id ,
post_id : pa . post_id ,
user_id : pa . user_id ,
post_action_type_id : pa . post_action_type_id ,
created_at : pa . created_at ,
disposed_by_id : pa . disposed_by_id ,
disposed_at : pa . disposed_at ,
disposition : pa . disposition ,
related_post_id : pa . related_post_id ,
targets_topic : pa . targets_topic ,
staff_took_action : pa . staff_took_action
}
2013-08-19 21:14:26 +10:00
action [ :name_key ] = PostActionType . types . key ( pa . post_action_type_id )
2014-07-28 19:17:37 +02:00
if pa . related_post && pa . related_post . topic
conversation = {}
related_topic = pa . related_post . topic
2014-07-28 22:50:49 +02:00
if response = related_topic . ordered_posts [ 0 ]
2014-07-28 19:17:37 +02:00
conversation [ :response ] = {
excerpt : excerpt ( response . cooked ),
user_id : response . user_id
}
user_ids << response . user_id
2014-07-28 22:50:49 +02:00
if reply = related_topic . ordered_posts [ 1 ]
2014-07-28 19:17:37 +02:00
conversation [ :reply ] = {
excerpt : excerpt ( reply . cooked ),
user_id : reply . user_id
}
user_ids << reply . user_id
conversation [ :has_more ] = related_topic . posts_count > 2
end
end
action . merge! ( permalink : related_topic . relative_url , conversation : conversation )
2013-08-19 21:14:26 +10:00
end
2014-07-28 19:17:37 +02:00
2017-09-11 16:44:20 -04:00
if opts [ :rest_api ]
post . post_action_ids << action [ :id ]
all_post_actions << action
else
post . post_actions << action
end
2014-07-28 19:17:37 +02:00
user_ids << pa . user_id
user_ids << pa . disposed_by_id if pa . disposed_by_id
2013-08-19 21:14:26 +10:00
end
2014-07-28 19:17:37 +02:00
# maintain order
posts = post_ids . map { | id | post_lookup [ id ] }
# TODO: add serializer so we can skip this
2013-08-19 21:14:26 +10:00
posts . map! ( & :marshal_dump )
2014-07-28 19:17:37 +02:00
2018-06-13 11:44:13 -04:00
users = User . includes ( :user_stat ) . where ( id : user_ids . to_a ) . to_a
User . preload_custom_fields ( users , User . whitelisted_user_custom_fields ( guardian ))
2014-07-28 19:17:37 +02:00
[
posts ,
Topic . with_deleted . where ( id : topic_ids . to_a ) . to_a ,
2018-06-13 11:44:13 -04:00
users ,
2017-09-12 13:04:53 -04:00
all_post_actions ,
total_rows
2014-07-28 19:17:37 +02:00
]
2013-08-19 21:14:26 +10:00
end
2017-09-12 13:04:53 -04:00
def self . flagged_post_actions ( opts = nil )
opts ||= {}
2015-02-16 13:03:04 +01:00
post_actions = PostAction . flags
2017-07-28 10:20:09 +09:00
. 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" )
. where ( "posts.user_id > 0" )
2015-02-16 13:03:04 +01:00
2017-09-08 16:47:49 -04:00
if opts [ :topic_id ]
post_actions = post_actions . where ( "topics.id = ?" , opts [ :topic_id ] )
end
2018-01-17 13:03:14 -05:00
if opts [ :user_id ]
post_actions = post_actions . where ( "posts.user_id = ?" , opts [ :user_id ] )
end
if opts [ :filter ] == 'without_custom'
return post_actions . where (
'post_action_type_id' => PostActionType . flag_types_without_custom . values
)
end
2017-09-08 16:47:49 -04:00
if opts [ :filter ] == "old"
2015-02-16 13:03:04 +01:00
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
2017-07-28 10:20:09 +09:00
. where ( "posts.deleted_at" => nil )
. where ( "topics.deleted_at" => nil )
2014-07-28 19:17:37 +02:00
end
2013-08-19 21:14:26 +10:00
2015-02-16 13:03:04 +01:00
end
2017-09-06 10:21:07 -04:00
def self . flagged_topics
results = PostAction
. flags
. active
. includes ( post : [ :user , :topic ] )
2017-09-25 16:15:48 -04:00
. references ( :post )
. where ( "posts.user_id > 0" )
2017-09-06 10:21:07 -04:00
. order ( 'post_actions.created_at DESC' )
ft_by_id = {}
users_by_id = {}
topics_by_id = {}
2018-05-07 15:14:18 -04:00
counts_by_post = {}
2017-09-06 10:21:07 -04:00
results . each do | pa |
if pa . post . present? && pa . post . topic . present?
2018-05-07 15:14:18 -04:00
topic_id = pa . post . topic . id
ft = ft_by_id [ topic_id ] ||= OpenStruct . new (
2017-09-06 10:21:07 -04:00
topic : pa . post . topic ,
flag_counts : {},
user_ids : [] ,
2018-05-07 15:14:18 -04:00
last_flag_at : pa . created_at ,
meets_minimum : false
2017-09-06 10:21:07 -04:00
)
2018-05-07 15:14:18 -04:00
counts_by_post [ pa . post . id ] ||= 0
sum = counts_by_post [ pa . post . id ] += 1
ft . meets_minimum = true if sum >= SiteSetting . min_flags_staff_visibility
2017-09-06 10:21:07 -04:00
2018-05-07 15:14:18 -04:00
topics_by_id [ topic_id ] = pa . post . topic
2017-09-06 10:21:07 -04:00
ft . flag_counts [ pa . post_action_type_id ] ||= 0
ft . flag_counts [ pa . post_action_type_id ] += 1
ft . user_ids << pa . post . user_id
ft . user_ids . uniq!
users_by_id [ pa . post . user_id ] ||= pa . post . user
end
end
2018-05-07 15:14:18 -04:00
flagged_topics = ft_by_id . values . select { | ft | ft . meets_minimum }
2017-09-06 10:21:07 -04:00
Topic . preload_custom_fields ( topics_by_id . values , TopicList . preloaded_custom_fields )
2018-05-07 15:14:18 -04:00
{ flagged_topics : flagged_topics , users : users_by_id . values }
2017-09-06 10:21:07 -04:00
end
2014-07-28 19:17:37 +02:00
private
2013-08-19 21:14:26 +10:00
2018-06-07 13:28:18 +08:00
def self . excerpt ( cooked )
excerpt = Post . excerpt ( cooked , 200 , keep_emoji_images : true )
# remove the first link if it's the first node
fragment = Nokogiri :: HTML . fragment ( excerpt )
if fragment . children . first == fragment . css ( "a:first" ) . first && fragment . children . first
fragment . children . first . remove
2013-08-19 21:14:26 +10:00
end
2018-06-07 13:28:18 +08:00
fragment . to_html . strip
end
2014-07-28 19:17:37 +02:00
2013-08-19 21:14:26 +10:00
end