Informe del Panel - Actividad del Moderador

Este es una versión SQL del Informe del Panel de Actividad del Moderador.

Este informe proporciona una visión general completa de las actividades realizadas por los moderadores dentro de un período de tiempo específico en un sitio de Discourse. El informe combina múltiples aspectos de la actividad del moderador: tiempo dedicado en la plataforma, número de indicadores revisados, publicaciones creadas, mensajes personales (PM) creados, temas creados y revisiones de publicaciones realizadas.

Este informe del panel es una herramienta valiosa para los administradores que buscan medir la efectividad y el compromiso de su equipo de moderación, brindando una mirada detallada a su actividad y contribuciones. Las ideas proporcionadas por el informe pueden informar las decisiones sobre la capacitación, el reconocimiento y el reclutamiento de moderadores, y garantizar que el equipo de moderación esté bien equilibrado y sea efectivo para mantener los estándares de la comunidad.

--[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

Parámetros

  • :start_date y :end_date - Estos parámetros definen el rango de fechas para el informe. Ambos parámetros de fecha aceptan el formato de fecha YYYY-MM-DD.
  • :include_admins - Este parámetro determina si se incluyen los administradores en el informe junto con los moderadores.

Explicación de la Consulta SQL

El informe está estructurado utilizando expresiones de tabla comunes (CTE) para segmentar el procesamiento de datos en secciones manejables y lógicas. Esto es lo que sucede en cada CTE:

  1. mods: Identifica a todos los usuarios con estado de moderador o estado de administrador (si se incluye mediante el parámetro :include_admins). Selecciona solo las columnas de usuario relevantes para consultas posteriores.
  2. time_read: Calcula el tiempo total (en segundos) que cada moderador ha pasado leyendo contenido en la plataforma entre las fechas de inicio y fin proporcionadas.
  3. flag_count: Cuenta el número de indicadores que los moderadores han aceptado o rechazado durante el período especificado. Tiene en cuenta múltiples tipos de indicadores representados por sus respectivos IDs de tipo de acción de publicación.
  4. revision_count: Cuenta el número de revisiones de publicaciones realizadas por moderadores en las publicaciones de otros usuarios dentro del plazo dado.
  5. topic_count: Cuenta el número de temas regulares creados por los moderadores.
  6. post_count: Cuenta el número de publicaciones creadas por los moderadores en temas regulares.
  7. pm_count: Cuenta el número de mensajes privados iniciados por los moderadores.

Después de recopilar los datos en las CTE, la consulta principal las une basándose en el ID de usuario y compila el informe final que muestra el nombre de usuario de cada moderador, el tiempo total dedicado a leer (convertido a horas), el número de indicadores revisados, temas creados, mensajes personales creados, publicaciones creadas y revisiones realizadas. Los resultados se ordenan alfabéticamente por el nombre de usuario del moderador.

Resultados de Ejemplo

usuario 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 Me gusta

Hola @SaraDev,

Esto es muy útil. ¿Sería posible añadir las columnas ‘Publicaciones aprobadas’ y ‘Publicaciones rechazadas’ al informe de actividad del moderador?

Gracias,
T_Disco

3 Me gusta

Hola @T_Disco,

Sí, para agregar los resultados de Publicaciones aprobadas y Publicaciones rechazadas al informe de Actividad del Moderador, podemos utilizar las tablas reviewables y reviewable_scores. Específicamente, el campo status en reviewable_scores se puede usar para determinar si una publicación fue aprobada (status = 1) o rechazada (status = 2).

Así es como se vería esto añadido al informe:

Actividad del Moderador con Publicaciones Aprobadas y Publicaciones Rechazadas

-- [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

Donde los resultados para este informe se verían así:

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 me gusta

¡Eso es genial, gracias @SaraDev!

¿Se añadirán esas columnas al informe de Actividad del Moderador en la pestaña /admin/dashboard/moderation en algún momento?

Gracias de nuevo :slight_smile:
T_Disco

1 me gusta

@SaraDev
¿Es posible una consulta para el número de fusiones de temas realizadas en un período de tiempo determinado?

2 Me gusta

Actualmente no tenemos planes de añadir esas columnas a la versión del informe en el panel, pero puedo comentarlo con nuestro equipo para ver si podemos hacer algunas mejoras en el futuro. :slightly_smiling_face:

Sí, para crear una consulta que muestre cuándo se movieron las publicaciones a otros temas, puedes filtrar la tabla posts por entradas donde el action_code indique un movimiento con una entrada split_topic.

Por ejemplo:

Acciones individuales de movimiento de publicaciones

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

Mostraría resultados como:

publicación usuario tema número_de_publicación creado_en actualizado_en código_de_acción
Una publicación se fusionó en un tema existente:: [Título del Tema Fusionado] NOMBREDEUSUARIO Título del Tema Original 3 2024-10-30 2024-10-30 split_topic
2 publicaciones se fusionaron en un tema existente:: [Título del Tema Fusionado] NOMBREDEUSUARIO Título del Tema Original 5 2024-10-30 2024-10-30 split_topic
Una publicación se dividió en un nuevo tema: [Título del Tema Dividido] NOMBREDEUSUARIO Título del Tema Original 2 2024-10-30 2024-10-30 split_topic

Si quisieras mostrar un recuento total de movimientos de publicaciones por usuario en un sitio, y añadir un par de parámetros para filtrar las acciones de movimiento por fecha, también podrías usar una consulta como la siguiente:

Número de acciones de movimiento de publicaciones por usuario

-- [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

Donde los resultados de ejemplo se verían así:

usuario recuento_movimientos
NombreDeUsuario_1 5
NombreDeUsuario_2 2

Ten en cuenta que con ambas consultas, mover cualquier número de publicaciones de un tema a otro solo se cuenta como una acción, independientemente del número de publicaciones que se movieron. Mover el contenido de un tema completo a otro tema también solo se cuenta como una acción.

El número de publicaciones que se movieron durante cada acción se puede ver en la consulta Acciones individuales de movimiento de publicaciones en la columna post con el texto X publicaciones se fusionaron en un tema existente..., sin embargo, esta información no está presente en la segunda consulta.

En la consulta Acciones individuales de movimiento de publicaciones, también puedes ver publicaciones con el texto: Una publicación se dividió en un nuevo tema..., que indican que la publicación se dividió en un nuevo tema en lugar de moverse a un tema existente, ya que Discourse considera ambas acciones como split_topic, ya que las publicaciones se mueven de un tema a otro.

2 Me gusta

Se dividieron 5 publicaciones en un nuevo tema: Métricas de página de usuario