discourse/app/models/concerns/reports/moderators_activity.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

205 lines
5.9 KiB
Ruby

# frozen_string_literal: true
module Reports::ModeratorsActivity
extend ActiveSupport::Concern
class_methods do
def report_moderators_activity(report)
report.labels = [
{
type: :user,
properties: {
username: :username,
id: :user_id,
avatar: :user_avatar_template,
},
title: I18n.t("reports.moderators_activity.labels.moderator"),
},
{
property: :flag_count,
type: :number,
title: I18n.t("reports.moderators_activity.labels.flag_count"),
},
{
type: :seconds,
property: :time_read,
title: I18n.t("reports.moderators_activity.labels.time_read"),
},
{
property: :topic_count,
type: :number,
title: I18n.t("reports.moderators_activity.labels.topic_count"),
},
{
property: :pm_count,
type: :number,
title: I18n.t("reports.moderators_activity.labels.pm_count"),
},
{
property: :post_count,
type: :number,
title: I18n.t("reports.moderators_activity.labels.post_count"),
},
{
property: :revision_count,
type: :number,
title: I18n.t("reports.moderators_activity.labels.revision_count"),
},
]
report.modes = [Report::MODES[:table]]
report.data = []
query = <<~SQL
WITH mods AS (
SELECT
id AS user_id,
username_lower AS username,
uploaded_avatar_id
FROM users u
WHERE u.moderator = 'true'
AND u.id > 0
),
time_read AS (
SELECT SUM(uv.time_read) AS time_read,
uv.user_id
FROM mods m
JOIN user_visits uv
ON m.user_id = uv.user_id
WHERE uv.visited_at >= '#{report.start_date}'
AND uv.visited_at <= '#{report.end_date}'
GROUP BY uv.user_id
),
flag_count AS (
WITH period_actions AS (
SELECT agreed_by_id,
disagreed_by_id,
deferred_by_id
FROM post_actions
WHERE post_action_type_id IN (#{PostActionType.flag_types_without_additional_message.values.join(",")})
AND created_at >= '#{report.start_date}'
AND created_at <= '#{report.end_date}'
),
agreed_flags AS (
SELECT pa.agreed_by_id AS user_id,
COUNT(*) AS flag_count
FROM mods m
JOIN period_actions pa
ON pa.agreed_by_id = m.user_id
GROUP BY agreed_by_id
),
disagreed_flags AS (
SELECT pa.disagreed_by_id AS user_id,
COUNT(*) AS flag_count
FROM mods m
JOIN period_actions pa
ON pa.disagreed_by_id = m.user_id
GROUP BY disagreed_by_id
),
deferred_flags AS (
SELECT pa.deferred_by_id AS user_id,
COUNT(*) AS flag_count
FROM mods m
JOIN period_actions pa
ON pa.deferred_by_id = m.user_id
GROUP BY deferred_by_id
)
SELECT
COALESCE(af.user_id, df.user_id, def.user_id) AS user_id,
COALESCE(af.flag_count, 0) + COALESCE(df.flag_count, 0) + COALESCE(def.flag_count, 0) AS flag_count
FROM agreed_flags af
FULL OUTER JOIN disagreed_flags df
ON df.user_id = af.user_id
FULL OUTER JOIN deferred_flags def
ON def.user_id = af.user_id
),
revision_count AS (
SELECT pr.user_id,
COUNT(*) AS revision_count
FROM mods m
JOIN post_revisions pr
ON pr.user_id = m.user_id
JOIN posts p
ON p.id = pr.post_id
WHERE pr.created_at >= '#{report.start_date}'
AND pr.created_at <= '#{report.end_date}'
AND p.user_id <> pr.user_id
GROUP BY pr.user_id
),
topic_count AS (
SELECT t.user_id,
COUNT(*) AS topic_count
FROM mods m
JOIN topics t
ON t.user_id = m.user_id
WHERE t.archetype = 'regular'
AND t.created_at >= '#{report.start_date}'
AND t.created_at <= '#{report.end_date}'
GROUP BY t.user_id
),
post_count AS (
SELECT p.user_id,
COUNT(*) AS post_count
FROM mods m
JOIN posts p
ON p.user_id = m.user_id
JOIN topics t
ON t.id = p.topic_id
WHERE t.archetype = 'regular'
AND p.created_at >= '#{report.start_date}'
AND p.created_at <= '#{report.end_date}'
GROUP BY p.user_id
),
pm_count AS (
SELECT p.user_id,
COUNT(*) AS pm_count
FROM mods m
JOIN posts p
ON p.user_id = m.user_id
JOIN topics t
ON t.id = p.topic_id
WHERE t.archetype = 'private_message'
AND p.created_at >= '#{report.start_date}'
AND p.created_at <= '#{report.end_date}'
GROUP BY p.user_id
)
SELECT
m.user_id,
m.username,
m.uploaded_avatar_id,
tr.time_read,
fc.flag_count,
rc.revision_count,
tc.topic_count,
pc.post_count,
pmc.pm_count
FROM mods m
LEFT JOIN time_read tr ON tr.user_id = m.user_id
LEFT JOIN flag_count fc ON fc.user_id = m.user_id
LEFT JOIN revision_count rc ON rc.user_id = m.user_id
LEFT JOIN topic_count tc ON tc.user_id = m.user_id
LEFT JOIN post_count pc ON pc.user_id = m.user_id
LEFT JOIN pm_count pmc ON pmc.user_id = m.user_id
ORDER BY m.username
SQL
DB
.query(query)
.each do |row|
mod = {}
mod[:username] = row.username
mod[:user_id] = row.user_id
mod[:user_avatar_template] = User.avatar_template(row.username, row.uploaded_avatar_id)
mod[:time_read] = row.time_read
mod[:flag_count] = row.flag_count
mod[:revision_count] = row.revision_count
mod[:topic_count] = row.topic_count
mod[:post_count] = row.post_count
mod[:pm_count] = row.pm_count
report.data << mod
end
end
end
end