Al usar el plugin de Gamificación, se otorgan puntos por las invitaciones canjeadas.
Esto se puede abusar fácilmente enviando invitaciones y canjeándolas con una cuenta duplicada (falsa).
Cuando un administrador elimina dicha cuenta falsa, el comportamiento del plugin de gamificación (y el sistema de invitación) depende de cómo se envió la invitación.
Si la invitación estaba vinculada a una dirección de correo electrónico específica y se elimina al usuario, tanto el registro invite como los registros user_invite se eliminan de forma definitiva (!). La próxima vez que se ejecute el trabajo de Sidekiq UpdateScoresFor*, el plugin de gamificación deducirá nuevamente los puntos otorgados de la puntuación.
Si la invitación no estaba vinculada a una dirección de correo electrónico específica y se elimina al usuario, se eliminará el registro invited_users, pero el registro invite permanecerá. El valor de redemption_count no disminuirá. Esto tiene sentido desde un punto de vista porque el canje de la invitación se ha realizado, aunque el usuario se haya eliminado posteriormente. Pero el plugin de Gamificación usa el redemption_count para calcular la puntuación, por lo que los puntos no se deducirán.
Mientras depuraba esto, también descubrí que el trabajo de puntuación solo considerará las invitaciones que tengan menos de 10 días. Entonces, si una invitación se canjea después de 11 días, no se otorgarán puntos en absoluto. Iba a decir 'Supongo que debe mirar updated_at en lugar de created_at, pero cuando se incrementa el recuento de canje para la invitación, no se toca la marca de tiempo updated_at.
¿Funcionaría algo como esto mejor (ajustado para adaptarse al formato de consulta puntuable - esta es una prueba para el explorador de datos ):
-- [params]
-- date :start_date
-- date :end_date
SELECT
invited_by_id AS user_id,
COUNT(*) AS user_invites,
COUNT(*) * 10 AS invite_score
FROM invited_users iu
JOIN invites i ON i.id = iu.invite_id
JOIN users u ON u.id = iu.user_id
WHERE iu.redeemed_at::date BETWEEN :start_date AND :end_date
AND iu.user_id <> i.invited_by_id
AND u.created_at > iu.redeemed_at
GROUP BY invited_by_id
ORDER BY user_invites DESC
Cuando se elimina un usuario, se borra de la tabla invited_users, por lo que ya no estaría en el recuento. Si la eliminación ocurriera dentro de los 10 días, se corregiría automáticamente, si fuera más tiempo, necesitaría una actualización manual de la puntuación.
Usar la fecha redeemed_at tendría en cuenta aquellas invitaciones que se crearon hace más de 10 días.
AND iu.user_id <> i.invited_by_id también excluiría las autoinvitaciones.
Unir la tabla users y añadir AND u.created_at > iu.redeemed_at también excluiría la invitación a usuarios existentes.
Esto no funciona bien. A veces, el usuario se crea un poco antes de que ocurriera el canje. No tengo idea de por qué. Mayormente décimas de segundo, pero también encontré algunas de decenas de segundos.
Probado en una base de datos real.
select
iu.redeemed_at iu_AS redeemed_at,
u.created_at AS u_created_at,
u.created_at > iu.redeemed_at AS u_created_gt_iu_redeemed
from invited_users iu
left join users u on u.id = iu.user_id
where iu.redeemed_at is not null
order by iu.id desc;
iu_redeemed_at | u_created_at | u_created_gt_iu_redeemed
----------------------------+----------------------------+--------------------------
2023-09-08 00:00:47.557057 | 2023-09-08 00:00:48.376446 | t
2023-08-25 20:09:03.486362 | 2023-08-25 20:09:03.201357 | f
2023-08-15 23:38:32.271709 | 2023-08-15 23:38:33.570299 | t
2023-08-14 10:44:34.19912 | 2023-08-14 10:44:35.429371 | t
2023-08-12 13:41:10.428013 | 2023-08-12 13:41:11.733973 | t
2023-07-31 17:58:13.511289 | 2023-07-31 17:57:50.427111 | f
2023-07-23 00:56:33.455185 | 2023-07-23 00:55:47.999263 | f
2023-07-19 08:42:44.908096 | 2023-07-19 08:42:46.040201 | t
2023-06-30 09:11:38.829692 | 2023-06-30 09:11:39.618586 | t
2023-06-30 08:37:02.322192 | 2023-06-30 08:37:03.133769 | t
2023-06-29 16:24:01.705616 | 2023-06-29 16:24:02.55067 | t
2023-06-29 12:53:33.245688 | 2023-06-29 12:53:34.067159 | t
Encuentro esto demasiado “magia negra” ya que no sabemos qué está causando el retraso.
Sospecho que el retraso es causado por una gran cola de sidekiq o algo similar y, aunque la mayoría está por debajo de un segundo, aproximadamente el 3% está en el rango de 0:00:01 - 0:15:00 (un segundo a 15 minutos).
Y medio por ciento está en el orden de días, que parece el tipo de abuso que estamos tratando de prevenir. Así que, aunque esto es efectivo, haría más daño que bien debido a la cantidad de falsos positivos.