Por favor, avalie um script Ruby curto para suspender usuários inativos

Este é o meu primeiro script Ruby personalizado. :slight_smile: Em quase 50 anos de codificação com mais de 20 linguagens e dialetos, nunca precisei (ou quis :face_with_open_eyes_and_hand_over_mouth:) escrever em Ruby, mas tudo bem, você me pegou… por favor, seja gentil. :pray:

Meu objetivo é identificar contas de usuários que não foram autenticadas por links de e-mail e suspender as contas para que eu possa verificá-las antes de excluí-las. Durante a configuração inicial, tive configurações em vários estágios de desenvolvimento. Os e-mails de 2FA não foram enviados para alguns registros, e houve muitos registros falsos que agora gostaria de filtrar.

Versão 0.0.1

rails c

# Primeiro, garanta que os TLs de usuário estejam em conformidade com as definições mais recentes
User.all.find_each do |user|
  Promotion.recalculate(user)
end
Group.ensure_consistency!

# Preparar para o loop
logger = StaffActionLogger.new(User.where("id = 'admin'"))
# data temporária, os usuários serão removidos antes desta data
suspend_till = DateTime.new(2028, 12, 31)
suspend_at = DateTime.now
reason = 'Inativo'

# Identificar contas potencialmente mortas
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])
  # salvar o usuário, registrar a ação e... fazer o que for feito para este gatilho
  user.save!
  logger.log_user_suspend(user, reason)
  DiscourseEvent.trigger(:user_suspended, user: user)
  # evitar abusar do servidor de e-mail
  sleep(10)
end

Ao acionar o evento, gostaria que e-mails fossem enviados aos usuários - haverá muitos bounces e talvez algumas pessoas voltem para autenticar. Após uma semana, selecionarei todas as contas que ainda estão suspensas e as excluirei.

Perguntas:

  1. Em geral, isso fará o que se destina?
  2. Existe uma abordagem melhor?
  3. O registro é redundante com o gatilho do evento?
  4. Podemos fazer isso com JavaScript?
  5. Devo postar isso em outra categoria?
  6. Alguma outra palavra de conselho?

Obrigado!!

1 curtida

Hmm, ao olhar para isso, acho que deveria estar silenciando uma conta em vez de suspender. Se a conta for suspensa, o usuário não poderá fazer login para reivindicá-la.

Aqui está uma revisão…

Versão 0.0.2
silence_reason = 'Inativo'
User.where("views = 0 OR approved = FALSE OR last_seen_at IS NULL")
    .where("id > 0") # evitar usuários do 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

Sim, farei um backup antes de fazer qualquer uma dessas coisas.
Sim, sei que alguns TLs existentes serão reorganizados e terei que corrigi-los.

Além disso, em vez de silenciar, devo definir Approved=false ou Active=false? Acredito que isso forçará o usuário a clicar no link de e-mail em vez de fazer login manualmente, o que serve ao propósito de validar o endereço de e-mail.

Tudo isso está relacionado ao meu tópico recente: notes-on-silencing-or-deleting-users

[EDIT]
Também tenho “purge unactivated users grace period days” definido como 7.
Um silêncio ou suspensão reinicia isso? Se sim, se as pessoas não responderem a uma ação da conta em 7 dias, não tenho problemas em purgá-las.

Finalmente (sim, realmente) também tenho “clean up inactive users after days” definido como 365. Posso diminuir para 60 enquanto o fórum ainda está abrindo e apenas deixar as contas existentes saírem da lista. Em seguida, aumentá-lo de volta para 365. Essa é uma abordagem razoável para a poda automatizada de contas em um novo ambiente?

1 curtida

Por que isso não é suficiente para resolver seu problema?

Esses não deveriam ser AND em vez de OR?

O Discourse os impõe para validar endereços, então não está muito claro qual problema você está resolvendo. Você diz isso

Parece bastante improvável que você encontre usuários que queriam fazer login, mas não conseguiram antes, mas você pode saber de algo que eu não sei sobre sua configuração.

E o Discourse não enviará e-mails para endereços que não são validados, então não acho que isso enviará nenhum e-mail.

Eu sempre faço essas coisas em algumas contas, mas de mãos dadas para ver o que vai acontecer.

2 curtidas

Obrigado pelo seu interesse, @pfaffman!

Existem registros de usuários sem last_seen_at, criados meses atrás, approved=False, active=False, e eles não estão sendo removidos.
Existem registros de usuários com last_seen_at > 7 dias (meses atrás) e 0 visualizações, e eles não estão sendo removidos.

Quaisquer que sejam os critérios usados com essa flag de período de carência, eles não estão selecionando esses registros.
Alguém pode postar a consulta exata que está sendo usada para que eu possa entender quais outros fatores estão envolvidos?

Não, olhando diretamente no banco de dados, existem registros de usuários que se encaixam em cada critério, mas não em todos. Parece que a tabela de usuários no banco de dados está inconsistente. Existem registros com tópicos_entrados ou contagem_de_posts_lidos não zerados, mas com views=0. Existem registros com tópicos_entrados=0 e contagem_de_posts_lidos=0, mas views não é zero.

O ponto chave a lembrar é que, à medida que este site estava sendo desenvolvido, as configurações não eram ideais e humanos e bots estavam se registrando. A cláusula OR parece capturar todos eles. Agora que o site está estabilizado com (espero) configurações sensatas, não espero que novos registros resultem nas mesmas anomalias.

Pretendo executar o script muitas vezes com critérios diferentes. Consultarei os registros primeiro, fora do ambiente, e depois executarei o script de silenciamento para direcionar apenas os registros que realmente quero. Em algumas semanas, farei uma execução final, apenas selecionarei registros silenciados (qualquer pessoa que realmente voltou terá a flag removida) e os removirei todos:

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

Minha pergunta geral é se o script v0.0.2, com sua abordagem de seleção, registro e silenciamento, está correto para um sistema Discourse. Não sei se há algo mais a ser feito em um loop como este. Nunca criei e executei meu próprio script, então este é um pedido para que me verifiquem em busca de erros de novato.

Obrigado!!

1 curtida