mysociety/alaveteli

View on GitHub
lib/tasks/users.rake

Summary

Maintainability
Test Coverage
namespace :users do
  namespace :pro do
    desc 'Ensure all pro have the correct features enabled'
    task enable_features: :environment do
      User.pro.map { |u| u.features.assign_role_features }
    end
  end

  desc 'CSV containing count of users per email domain, most popular first'
  task count_per_domain: :environment do
    from = ENV["START_DATE"]

    results = UserStats.list_user_domains(start_date: from)

    puts %w(domain count_of_users).to_csv

    results.each do |result|
      puts [result['domain'], result['count']].to_csv
    end
  end

  desc "Lists per domain stats"
  task stats_by_domain: :environment do
    raise "must supply a DOMAIN value" unless ENV["DOMAIN"]
    domain = ENV["DOMAIN"]
    from = ENV["START_DATE"]

    users = User.where("email like ?", "%@#{domain}")
    users = users.where("created_at >= ?", from) if from

    total_users = users.count
    banned = users.banned.count

    banned_percent = if total_users == 0
      0
    else
      (banned.to_f / total_users * 100).round(2)
    end

    dormant = UserStats.count_dormant_users(domain, from)

    dormant_percent = if total_users == 0
      0
    else
      (dormant.to_f / total_users * 100).round(2)
    end

    p "Since #{from}..." if from
    p "total users: #{total_users}"
    p "   banned %: #{banned} (#{banned_percent}%)"
    p "  dormant %: #{dormant} (#{dormant_percent}%)"
  end

  desc "Bans all users for a specific domain"
  task ban_by_domain: :environment do
    raise "must supply a DOMAIN value" unless ENV["DOMAIN"]
    domain = ENV["DOMAIN"]
    from = ENV["START_DATE"]

    Rake.application.invoke_task("users:stats_by_domain")

    p ""

    message = "Do you want to ban all the non-admin users for #{domain}"
    message += " created on or after #{from}" if from
    message += "(y/N)"
    p message
    input = STDIN.gets.strip

    if input.downcase == "y"
      to_ban = UserStats.unbanned_by_domain(domain, from)
      count = to_ban.
        update_all(ban_text: "Banned for spamming")
      p "#{count} accounts banned"
    else
      p "No action taken"
    end
  end

  desc <<-EOF
  A list of most-active to least-active pro users.

  START_DATE: Specify the start of the period of activity to consider
  END_DATE: Specify the end of the period of activity to consider
  FIELDS: A CSV list of User attributes to print
          (default: "id,name,email,activity")
  EOF
  task pro_activity: :environment do
    fields =
      if ENV['FIELDS']
        ENV['FIELDS'].split(',').map(&:strip)
      else
        %w(id name email activity)
      end

    start_date =
      if ENV['START_DATE']
        Time.zone.parse(ENV['START_DATE']).at_beginning_of_day
      end

    end_date =
      (Time.zone.parse(ENV['END_DATE']).at_end_of_day if ENV['END_DATE'])

    # Only auto-calculate missing dates if one has been provided without the
    # other
    if start_date || end_date
      # If we don't have a start_date, set it to the earliest created User as
      # there can't be events before that
      start_date ||= User.minimum(:created_at)

      # If we don't have an end_date, set it to now.
      end_date ||= Time.zone.now
    end

    # Only create a date filter if one has been requested through the
    # environment
    between = start_date..end_date if start_date && end_date

    query = User::WithActivityQuery.new
    query = between ? query.call(between) : query.call
    users = query.pro.order(activity: :desc)

    # We can't `#pluck` activity because its not a real attribute, so we fall
    # back to a slower `#map`.
    users =
      if fields.include?('activity')
        users.map { |user| fields.map { |field| user.send(field) } }
      else
        users.pluck(*fields)
      end

    csv_string = CSV.generate do |csv|
      csv << fields
      users.each { |user| csv << Array(user) }
    end

    puts csv_string
  end

  desc 'Update hashed password to the latest algorithm (bcrypt)'
  task update_hashed_password: :environment do
    User.sha1.find_each { |user| user.update(password: user.hashed_password) }
  end
end