spaminator.rb 2.69 KB
require 'benchmark'

class AntiSpamPlugin::Spaminator

  class << self
    def run(environment)
      instance = new(environment)
      instance.run
    end

    def benchmark(environment)
      puts Benchmark.measure { run(environment) }
    end
  end


  def initialize(environment)
    @environment = environment
  end

  def run
    start_time = Time.now

    process_all_comments
    process_all_people
    process_people_without_network

    finish(start_time)
  end

  protected

  def finish(start_time)
    @environment.settings[:spaminator_last_run] = start_time
    @environment.save!
  end

  def conditions(table)
    last_run = @environment.settings[:spaminator_last_run]
    if last_run
      ["profiles.environment_id = ? AND #{table}.created_at > ?", @environment.id, last_run]
    else
      [ "profiles.environment_id = ?", @environment.id]
    end
  end

  def process_all_comments
    puts 'Processing comments ...'
    i = 0
    comments = Comment.joins("JOIN articles ON (comments.source_id = articles.id AND comments.source_type = 'Article') JOIN profiles ON (profiles.id = articles.profile_id)").where(conditions(:comments))
    total = comments.count
    comments.find_each do |comment|
      puts "Comment #{i += 1}/#{total} (#{100*i/total}%)"
      process_comment(comment)
    end
  end

  def process_all_people
    puts 'Processing people ...'
    i = 0
    people = Person.where(conditions(:profiles))
    total = people.count
    people.find_each do |person|
      puts "Person #{i += 1}/#{total} (#{100*i/total}%)"
      process_person(person)
    end
  end

  def process_comment(comment)
    comment.check_for_spam

    # TODO several comments with the same content:
    #   → disable author
    #   → mark all of them as spam
  end

  def process_person(person)
    # person is author of more than 2 comments marked as spam
    #   → burn
    #
    number_of_spam_comments = Comment.spam.where(author_id => person.id).count
    if number_of_spam_comments > 2
      mark_as_spammer(person)
    end
  end

  def process_people_without_network
    # people who signed up more than one month ago, have no friends and <= 1
    # communities
    #
    #   → burn
    #   → mark their comments as spam
    #
    Person.where(:environment_id => @environment.id).where(['created_at < ?', Time.now - 1.month]).find_each do |person|
      number_of_friends = person.friends.count
      number_of_communities = person.communities.count
      if number_of_friends == 0 && number_of_communities <= 1
        mark_as_spammer(person)
        Comment.where(:author_id => person.id).find_each do |comment|
          comment.spam!
        end
      end
    end
  end

  def mark_as_spammer(person)
    person.disable
  end

end