Dashboard-Bericht - Moderatoraktivität

Dies ist eine SQL-Version des Dashboard-Berichts für Moderatoraktivitäten.

Dieser Bericht bietet einen umfassenden Überblick über die Aktivitäten von Moderatoren innerhalb eines bestimmten Zeitraums auf einer Discourse-Website. Der Bericht kombiniert mehrere Aspekte der Moderatoraktivität: auf der Plattform verbrachte Zeit, Anzahl der geprüften Flags, erstellte Beiträge, erstellte persönliche Nachrichten (PMs), erstellte Themen und vorgenommene Beitragsrevisionen.

Dieser Dashboard-Bericht ist ein wertvolles Werkzeug für Administratoren, die die Effektivität und das Engagement ihres Moderationsteams messen möchten. Er bietet einen detaillierten Einblick in ihre Aktivitäten und Beiträge. Die durch den Bericht gewonnenen Erkenntnisse können Entscheidungen über Schulungen, Anerkennung und Rekrutierung von Moderatoren informieren und sicherstellen, dass das Moderationsteam gut ausbalanciert und effektiv bei der Aufrechterhaltung der Community-Standards ist.

--[params]
-- date :start_date = 2023-12-01
-- date :end_date = 2024-12-01
-- boolean :include_admins = false


WITH mods AS (
    SELECT
        id AS user_id,
        username_lower AS username,
        uploaded_avatar_id
    FROM users u
    WHERE ((u.moderator = true) OR (:include_admins AND u.admin = 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 >= :start_date
        AND uv.visited_at <= :end_date
    GROUP BY uv.user_id
),

flag_count AS (
    WITH period_actions AS (
        SELECT agreed_by_id,
        disagreed_by_id
        FROM post_actions
        WHERE post_action_type_id IN (3,4,8,6,7)
        AND created_at >= :start_date
        AND created_at <= :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
    )
    SELECT
    COALESCE(af.user_id, df.user_id) AS user_id,
    COALESCE(af.flag_count, 0) + COALESCE(df.flag_count, 0) AS flag_count
    FROM agreed_flags af
    FULL OUTER JOIN disagreed_flags df
    ON df.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 >= :start_date
      AND pr.created_at <= :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 >= :start_date
          AND t.created_at <= :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 >= :start_date
          AND p.created_at <= :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 >= :start_date
          AND p.created_at <= :end_date
      GROUP BY p.user_id
      )

SELECT
    m.user_id,
    m.username,
    fc.flag_count as flags_reviewed,
    ROUND(((tr.time_read) / 3600.00),2) as time_reading_hours,
    tc.topic_count as topics_created,
    pmc.pm_count as PMs_created,
    pc.post_count as posts_created,
    rc.revision_count as revisions
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 ASC

Parameter

  • :start_date und :end_date - Diese Parameter definieren den Datumsbereich für den Bericht. Beide Datumsparameter akzeptieren das Datumsformat YYYY-MM-DD.
  • :include_admins - Dieser Parameter bestimmt, ob Administratoren zusammen mit Moderatoren in den Bericht aufgenommen werden sollen.

SQL-Abfrageerklärung

Der Bericht ist mit Common Table Expressions (CTEs) strukturiert, um die Datenverarbeitung in überschaubare und logische Abschnitte zu unterteilen. Hier ist, was in jeder CTE geschieht:

  1. mods: Identifiziert alle Benutzer mit Moderatorstatus oder Administratorstatus (falls durch den Parameter :include_admins eingeschlossen). Es werden nur relevante Benutzerdaten für weitere Abfragen ausgewählt.
  2. time_read: Berechnet die Gesamtzeit (in Sekunden), die jeder Moderator zwischen den angegebenen Start- und Enddaten mit dem Lesen von Inhalten auf der Plattform verbracht hat.
  3. flag_count: Zählt die Anzahl der Flags, denen Moderatoren im angegebenen Zeitraum zugestimmt oder widersprochen haben. Es werden mehrere Flag-Typen berücksichtigt, die durch ihre jeweiligen Post-Aktionstyp-IDs dargestellt werden.
  4. revision_count: Zählt die Anzahl der Beitragsrevisionen, die von Moderatoren an Beiträgen anderer Benutzer im angegebenen Zeitraum vorgenommen wurden.
  5. topic_count: Zählt die Anzahl der von Moderatoren erstellten regulären Themen.
  6. post_count: Zählt die Anzahl der von Moderatoren in regulären Themen erstellten Beiträge.
  7. pm_count: Zählt die Anzahl der von Moderatoren initiierten privaten Nachrichten.

Nachdem die Daten in den CTEs gesammelt wurden, verknüpft die Hauptabfrage sie anhand der Benutzer-ID und stellt den endgültigen Bericht zusammen, der den Benutzernamen jedes Moderators, die Gesamtlesezeit (in Stunden umgerechnet), die Anzahl der geprüften Flags, erstellten Themen, erstellten persönlichen Nachrichten, erstellten Beiträge und vorgenommenen Revisionen anzeigt. Die Ergebnisse werden alphabetisch nach dem Benutzernamen des Moderators sortiert.

Beispielergebnisse

user username flags_reviewed time_reading_hours topics_created pms_created posts_created revisions
1 moderator1 NULL 36.11 NULL 344 8 15
2 moderator2 46 104.52 2 271 466 363
3 moderator3 NULL 72.15 NULL 418 64 16
7 „Gefällt mir“

Hallo @SaraDev,

Das ist wirklich nützlich. Wäre es möglich, die Spalten „Genehmigte Beiträge“ und „Abgelehnte Beiträge“ zum Bericht über Moderatorenaktivitäten hinzuzufügen?

Danke,
T_Disco

3 „Gefällt mir“

Hallo @T_Disco,

Ja, um die Ergebnisse für „Beiträge genehmigt“ und „Beiträge abgelehnt“ zum Bericht über die Moderationsaktivitäten hinzuzufügen, können wir die Tabellen reviewables und reviewable_scores verwenden. Insbesondere das Feld status in reviewable_scores kann verwendet werden, um zu bestimmen, ob ein Beitrag genehmigt (status = 1) oder abgelehnt (status = 2) wurde.

Hier ist, wie dies im Bericht aussehen würde:

Moderationsaktivität mit genehmigten und abgelehnten Beiträgen

-- [params]
-- date :start_date = 2023-12-01
-- date :end_date = 2024-12-01
-- boolean :include_admins = false

WITH mods AS (
    SELECT
        id AS user_id,
        username_lower AS username,
        uploaded_avatar_id
    FROM users u
    WHERE ((u.moderator = true) OR (:include_admins AND u.admin = 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 >= :start_date
        AND uv.visited_at <= :end_date
    GROUP BY uv.user_id
),

flag_count AS (
    WITH period_actions AS (
        SELECT agreed_by_id,
        disagreed_by_id
        FROM post_actions
        WHERE post_action_type_id IN (3,4,8,6,7)
        AND created_at >= :start_date
        AND created_at <= :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
    )
    SELECT
    COALESCE(af.user_id, df.user_id) AS user_id,
    COALESCE(af.flag_count, 0) + COALESCE(df.flag_count, 0) AS flag_count
    FROM agreed_flags af
    FULL OUTER JOIN disagreed_flags df
    ON df.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 >= :start_date
      AND pr.created_at <= :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 >= :start_date
          AND t.created_at <= :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 >= :start_date
          AND p.created_at <= :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 >= :start_date
          AND p.created_at <= :end_date
      GROUP BY p.user_id
),

reviewable_actions AS (
    SELECT
        rs.reviewed_by_id AS user_id,
        SUM(CASE WHEN rs.status = 1 THEN 1 ELSE 0 END) AS posts_approved,
        SUM(CASE WHEN rs.status = 2 THEN 1 ELSE 0 END) AS posts_rejected
    FROM mods m
    JOIN reviewable_scores rs ON rs.reviewed_by_id = m.user_id
    JOIN reviewables r ON r.id = rs.reviewable_id
    WHERE rs.reviewed_at >= :start_date
      AND rs.reviewed_at <= :end_date
    GROUP BY rs.reviewed_by_id
)

SELECT
    m.user_id,
    m.username,
    fc.flag_count as flags_reviewed,
    ROUND(((tr.time_read) / 3600.00),2) as time_reading_hours,
    tc.topic_count as topics_created,
    pmc.pm_count as PMs_created,
    pc.post_count as posts_created,
    rc.revision_count as revisions,
    ra.posts_approved,
    ra.posts_rejected
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
LEFT JOIN reviewable_actions ra ON ra.user_id = m.user_id
ORDER BY m.username ASC

Wo die Ergebnisse für diesen Bericht wie folgt aussehen würden:

user username flags_reviewed time_reading_hours topics_created pms_created posts_created revisions posts_approved posts_rejected
1 moderator1 NULL 36.11 NULL 344 8 15 10 5
2 moderator2 46 104.52 2 271 466 363 7 3
3 moderator3 NULL 72.15 NULL 418 64 16 NULL NULL
1 „Gefällt mir“

Das ist brillant, danke @SaraDev!

Werden diese Spalten irgendwann zum Moderatoraktivitätsbericht auf dem Tab /admin/dashboard/moderation hinzugefügt?

Danke nochmal :slight_smile:
T_Disco

1 „Gefällt mir“

@SaraDev
Ist eine Abfrage für die Anzahl der durchgeführten Topic-Zusammenführungen in einem bestimmten Zeitraum möglich?

2 „Gefällt mir“

Wir haben derzeit keine Pläne, diese Spalten zur Dashboard-Version des Berichts hinzuzufügen, aber ich kann dies mit unserem Team besprechen, um zu sehen, ob wir in Zukunft einige Verbesserungen vornehmen können. :slightly_smiling_face:

Ja, um eine Abfrage zu erstellen, die anzeigt, wann Beiträge in andere Topics verschoben wurden, können Sie die Tabelle posts nach Einträgen filtern, bei denen der action_code eine Verschiebung mit einem split_topic-Eintrag angibt.

Zum Beispiel:

Aktionen zum Verschieben einzelner Beiträge

SELECT
    id AS post_id,
    user_id,
    topic_id,
    post_number,
    created_at::date,
    updated_at::date,
    action_code
FROM
    posts
WHERE
    action_code = 'split_topic'
ORDER BY
    created_at DESC

Würde Ergebnisse wie diese anzeigen:

post user topic post_number created_at updated_at action_code
Ein Beitrag wurde in ein bestehendes Topic verschoben:: [Titel des verschobenen Topics] USERNAME Titel des ursprünglichen Topics 3 2024-10-30 2024-10-30 split_topic
2 Beiträge wurden in ein bestehendes Topic verschoben:: [Titel des verschobenen Topics] USERNAME Titel des ursprünglichen Topics 5 2024-10-30 2024-10-30 split_topic
Ein Beitrag wurde in ein neues Topic aufgeteilt: [Titel des aufgeteilten Topics] USERNAME Titel des ursprünglichen Topics 2 2024-10-30 2024-10-30 split_topic

Wenn Sie eine Gesamtzahl der Beitragverschiebungen für jeden Benutzer auf einer Website anzeigen und ein paar Parameter hinzufügen möchten, um die Verschiebungsaktionen nach Datum zu filtern, könnten Sie auch eine Abfrage wie die folgende verwenden:

Anzahl der Beitragverschiebungsaktionen pro Benutzer

-- [params]
-- date :start_date
-- date :end_date

SELECT
    user_id,
    COUNT(*) AS move_count
FROM
    posts
WHERE
    action_code = 'split_topic'
    AND created_at BETWEEN :start_date AND :end_date
GROUP BY
    user_id
ORDER BY
    move_count DESC

Wo Beispielergebnisse wie folgt aussehen würden:

user move_count
Username_1 5
Username_2 2

Beachten Sie, dass bei beiden Abfragen das Verschieben einer beliebigen Anzahl von Beiträgen von einem Topic in ein anderes nur als eine Aktion gezählt wird, unabhängig von der Anzahl der verschobenen Beiträge. Das Verschieben des Inhalts eines gesamten Topics in ein anderes Topic wird ebenfalls nur als eine Aktion gezählt.

Die Anzahl der Beiträge, die bei jeder Aktion verschoben wurden, kann in der Abfrage Aktionen zum Verschieben einzelner Beiträge unter der Spalte post mit dem Text X Beiträge wurden in ein bestehendes Topic verschoben... eingesehen werden. Diese Information ist jedoch in der zweiten Abfrage nicht vorhanden.

In der Abfrage Aktionen zum Verschieben einzelner Beiträge sehen Sie möglicherweise auch Beiträge mit dem Text: Ein Beitrag wurde in ein neues Topic aufgeteilt..., was darauf hinweist, dass der Beitrag in ein neues Topic aufgeteilt wurde, anstatt in ein bestehendes Topic verschoben zu werden, da Discourse beide Aktionen als split_topic-Aktionen betrachtet, da Beiträge von einem Topic in ein anderes verschoben werden.

2 „Gefällt mir“

5 Beiträge wurden in ein neues Thema aufgeteilt: User Page Metrics