Por favor, evalúe un script Ruby breve para suspender usuarios inactivos

Este es mi primer script personalizado de Ruby. :slight_smile: En casi 50 años de codificación con más de 20 lenguajes y dialectos, nunca he necesitado (o querido :face_with_open_eyes_and_hand_over_mouth:) escribir en Ruby, pero de acuerdo, me has convencido… por favor, sé amable. :pray:

Mi objetivo es identificar las cuentas de usuario que no han sido autenticadas por enlaces de correo electrónico y suspender las cuentas para poder revisarlas antes de eliminarlas. Durante la configuración inicial, tuve configuraciones en varias etapas de desarrollo. Los correos electrónicos de 2FA no se enviaron para algunos registros, y hubo muchos registros falsos que ahora me gustaría filtrar.

Versión 0.0.1

rails c

# Primero, asegúrate de que los TL de usuario se ajusten a las últimas definiciones
User.all.find_each do |user|
  Promotion.recalculate(user)
end
Group.ensure_consistency!

# Preparar para el bucle
logger = StaffActionLogger.new(User.where("id = 'admin'"))
# fecha temporal, los usuarios serán eliminados antes de esta fecha
suspend_till = DateTime.new(2028, 12, 31)
suspend_at = DateTime.now
reason = 'Inactivo'

# Identificar cuentas potencialmente muertas
User.where("views = 0 OR approved = FALSE OR last_seen_at IS NULL")
    .where("id > 0")
    .find_each do |user|
  user.suspended_till = suspend_till
  user.suspended_at = suspend_at
  user.change_trust_level!(TrustLevel[0])
  # guardar el usuario, registrar la acción y... hacer lo que se haga para este disparador
  user.save!
  logger.log_user_suspend(user, reason)
  DiscourseEvent.trigger(:user_suspended, user: user)
  # evitar abusar del servidor de correo
  sleep(10)
end

Al activar el evento, me gustaría que se enviaran correos electrónicos a los usuarios; habrá muchos rebotes y quizás algunas personas regresen para autenticarse. Después de una semana, seleccionaré todas las cuentas que aún estén suspendidas y las eliminaré.

Preguntas:

  1. En general, ¿hará esto lo que se pretende?
  2. ¿Hay un mejor enfoque?
  3. ¿Es el registro redundante con el disparador del evento?
  4. ¿Podemos hacer esto con JavaScript?
  5. ¿Debería publicar esto en otra categoría?
  6. ¿Algún otro consejo?

¡¡Gracias!!

1 me gusta

Hmm, al ver eso, creo que debería silenciar una cuenta en lugar de suspenderla. Si la cuenta está suspendida, el usuario no puede iniciar sesión para reclamarla.

Aquí hay una revisión…

Versión 0.0.2
silence_reason = 'Inactivo'
User.where("views = 0 OR approved = FALSE OR last_seen_at IS NULL")
    .where("id > 0") # evitar usuarios del sistema
    .find_each do |user|
  user.silence(reason: silence_reason)
  user.change_trust_level!(TrustLevel[0])
  user.save!
  logger.log_user_silence(user, silence_reason)
  DiscourseEvent.trigger(:user_silenced, user: user)
  sleep(5)
end

Sí, haré una copia de seguridad antes de hacer nada de esto.
Sí, sé que algunos TL existentes se reorganizarán y tendré que arreglarlos.

Además, en lugar de silenciar, ¿debería establecer Approved=false o Active=false? Creo que eso obligaría al usuario a hacer clic en el enlace del correo electrónico en lugar de hacerlo manualmente, lo que cumple el propósito de validar la dirección de correo electrónico.

Todo esto está relacionado con mi hilo reciente: notas-sobre-silenciar-o-eliminar-usuarios

[EDITAR]
También tengo “purgar usuarios no activados período de gracia días” establecido en 7.
¿Un silencio o suspensión reinicia esto? Si es así, si las personas no responden a una acción de cuenta dentro de los 7 días, no tengo ningún problema en purgarlas.

Finalmente (sí, de verdad) también tengo “limpiar usuarios inactivos después de días” establecido en 365. Puedo reducirlo a 60 mientras el foro todavía se está abriendo y simplemente dejar que las cuentas existentes desaparezcan de la lista. Luego, volver a aumentarlo a 365. ¿Es ese un enfoque razonable para la poda automática de cuentas en un entorno nuevo?

1 me gusta

¿Por qué eso no es suficiente para resolver tu problema?

¿No deberían ser AND en lugar de OR?

Discourse los aplica para validar direcciones, así que no tengo muy claro qué problema estás resolviendo. Dices esto

Parece bastante improbable que encuentres usuarios que quisieran iniciar sesión pero no pudieran antes, pero puede que sepas algo que yo no sobre tu configuración.

Y Discourse no enviará correos electrónicos a direcciones que no estén validadas, así que no creo que esto envíe ningún correo electrónico.

Siempre hago estas cosas en algunas cuentas, pero a mano para ver qué va a pasar.

2 Me gusta

Gracias por tu interés, @pfaffman!

Hay registros de usuarios sin last_seen_at, creados hace meses, approved=False, active=False, y no se están purgando.
Hay registros de usuarios con last_seen_at > 7 días (meses de antigüedad) y 0 vistas, y no se están purgando.

Cualquiera que sea el criterio utilizado con esa bandera de período de gracia, no está seleccionando estos registros.
¿Puede alguien publicar la consulta exacta que se está utilizando para que pueda entender qué otros factores están involucrados?

No, mirando la base de datos directamente hay registros de usuarios que cumplen cada criterio pero no todos. Parece que la tabla de usuarios en la base de datos es inconsistente. Hay registros con topics_entered o posts_read_count distintos de cero, pero con views=0. Hay registros con topics_entered=0 y posts_read_count=0, pero views es distinto de cero.

El punto clave a recordar es que a medida que este sitio se desarrollaba, la configuración no era óptima y se registraban humanos y bots. La cláusula OR parece capturar a todos estos. Ahora que el sitio está estabilizado con (espero) configuraciones sensatas, no espero que los nuevos registros generen las mismas anomalías.

Tengo la intención de ejecutar el script muchas veces con diferentes criterios. Consultaré los registros primero, fuera del entorno, y luego ejecutaré el script de silencio para apuntar solo a los registros que realmente quiero. En un par de semanas haré una ejecución final, solo seleccionaré registros silenciados (a cualquiera que realmente haya regresado se le quitará la bandera) y purgaré a todos:

UserDestroyer.new(admin_user).destroy(user, reassign_to: archive_user)

Mi pregunta general es si el script v0.0.2, con su enfoque de selección, registro y silencio, es correcto para un sistema Discourse. No sé si hay algo más que hacer en un bucle como este. Nunca he creado y ejecutado mi propio script, así que esta es una solicitud para que me revisen si cometí errores de novato.

¡Gracias!

1 me gusta