discourse/app/models/concerns/reports/flags_status.rb
Martin Brennan 15838aa756
DEV: Convert AdminReport component to gjs (#31011)
This commit converts the `AdminReport` component, which is quite
high complexity, to gjs. After this initial round, ideally this
component would be broken up into smaller components because it is
getting quite big now.

Also in this commit:

* Add an option to display the report description in a tooltip, which
was
   the main way the description was shown until recently. We want to use
   this on the dashboard view mostly.
* Move admin report "mode" definitions to the server-side Report model,
inside a `Report::MODES` constant, collecting the modes defined in
various
   places in the UI into one place
* Refactor report code to refer to mode definitions
* Add a `REPORT_MODES` constant in JS via javascript.rake and refactor
  JS to refer to the modes
* Delete old admin report components that are no longer used
  (trust-level-counts, counts, per-day-counts) which were replaced
  by admin-report-counters a while ago
* Add a new `registerReportModeComponent` plugin API, some plugins
   introduce their own modes (like AI's `emotion`) and components and
   we need a way to render them
2025-01-29 10:33:43 +10:00

190 lines
5.3 KiB
Ruby

# frozen_string_literal: true
module Reports::FlagsStatus
extend ActiveSupport::Concern
class_methods do
def report_flags_status(report)
report.modes = [Report::MODES[:table]]
report.labels = [
{
type: :post,
properties: {
topic_id: :topic_id,
number: :post_number,
truncated_raw: :post_type,
},
title: I18n.t("reports.flags_status.labels.flag"),
},
{
type: :user,
properties: {
username: :staff_username,
id: :staff_id,
avatar: :staff_avatar_template,
},
title: I18n.t("reports.flags_status.labels.assigned"),
},
{
type: :user,
properties: {
username: :poster_username,
id: :poster_id,
avatar: :poster_avatar_template,
},
title: I18n.t("reports.flags_status.labels.poster"),
},
{
type: :user,
properties: {
username: :flagger_username,
id: :flagger_id,
avatar: :flagger_avatar_template,
},
title: I18n.t("reports.flags_status.labels.flagger"),
},
{
type: :seconds,
property: :response_time,
title: I18n.t("reports.flags_status.labels.time_to_resolution"),
},
]
report.data = []
flag_types = PostActionType.flag_types
sql = <<~SQL
WITH period_actions AS (
SELECT id,
post_action_type_id,
created_at,
agreed_at,
disagreed_at,
deferred_at,
agreed_by_id,
disagreed_by_id,
deferred_by_id,
post_id,
user_id,
COALESCE(disagreed_at, agreed_at, deferred_at) AS responded_at
FROM post_actions
WHERE post_action_type_id IN (#{flag_types.values.join(",")})
AND created_at >= '#{report.start_date}'
AND created_at <= '#{report.end_date}'
ORDER BY created_at DESC
),
poster_data AS (
SELECT pa.id,
p.user_id AS poster_id,
p.topic_id as topic_id,
p.post_number as post_number,
u.username_lower AS poster_username,
u.uploaded_avatar_id AS poster_avatar_id
FROM period_actions pa
JOIN posts p
ON p.id = pa.post_id
JOIN users u
ON u.id = p.user_id
),
flagger_data AS (
SELECT pa.id,
u.id AS flagger_id,
u.username_lower AS flagger_username,
u.uploaded_avatar_id AS flagger_avatar_id
FROM period_actions pa
JOIN users u
ON u.id = pa.user_id
),
staff_data AS (
SELECT pa.id,
u.id AS staff_id,
u.username_lower AS staff_username,
u.uploaded_avatar_id AS staff_avatar_id
FROM period_actions pa
JOIN users u
ON u.id = COALESCE(pa.agreed_by_id, pa.disagreed_by_id, pa.deferred_by_id)
)
SELECT
sd.staff_username,
sd.staff_id,
sd.staff_avatar_id,
pd.poster_username,
pd.poster_id,
pd.poster_avatar_id,
pd.post_number,
pd.topic_id,
fd.flagger_username,
fd.flagger_id,
fd.flagger_avatar_id,
pa.post_action_type_id,
pa.created_at,
pa.agreed_at,
pa.disagreed_at,
pa.deferred_at,
pa.agreed_by_id,
pa.disagreed_by_id,
pa.deferred_by_id,
COALESCE(pa.disagreed_at, pa.agreed_at, pa.deferred_at) AS responded_at
FROM period_actions pa
FULL OUTER JOIN staff_data sd
ON sd.id = pa.id
FULL OUTER JOIN flagger_data fd
ON fd.id = pa.id
FULL OUTER JOIN poster_data pd
ON pd.id = pa.id
SQL
DB
.query(sql)
.each do |row|
data = {}
data[:post_type] = flag_types.key(row.post_action_type_id).to_s
data[:post_number] = row.post_number
data[:topic_id] = row.topic_id
if row.staff_id
data[:staff_username] = row.staff_username
data[:staff_id] = row.staff_id
data[:staff_avatar_template] = User.avatar_template(
row.staff_username,
row.staff_avatar_id,
)
end
if row.poster_id
data[:poster_username] = row.poster_username
data[:poster_id] = row.poster_id
data[:poster_avatar_template] = User.avatar_template(
row.poster_username,
row.poster_avatar_id,
)
end
if row.flagger_id
data[:flagger_id] = row.flagger_id
data[:flagger_username] = row.flagger_username
data[:flagger_avatar_template] = User.avatar_template(
row.flagger_username,
row.flagger_avatar_id,
)
end
if row.agreed_by_id
data[:resolution] = I18n.t("reports.flags_status.values.agreed")
elsif row.disagreed_by_id
data[:resolution] = I18n.t("reports.flags_status.values.disagreed")
elsif row.deferred_by_id
data[:resolution] = I18n.t("reports.flags_status.values.deferred")
else
data[:resolution] = I18n.t("reports.flags_status.values.no_action")
end
data[:response_time] = row.responded_at ? row.responded_at - row.created_at : nil
report.data << data
end
end
end
end