plugins/spaminator/lib/spaminator_plugin/spaminator.rb
# encoding: utf-8
class SpaminatorPlugin::Spaminator
class << self
def run(environment)
instance = new(environment)
instance.run
end
def benchmark(environment)
puts Benchmark.measure { run(environment) }
end
def initialize_logger(environment)
logdir = Rails.root.join("log", SpaminatorPlugin.name.underscore)
FileUtils.mkdir_p(logdir) if !File.exist?(logdir)
logpath = File.join(logdir, "#{environment.name.to_slug}_#{ENV['RAILS_ENV']}_#{Time.now.strftime('%F_%T')}.log")
@logger = Logger.new(logpath)
end
def log(message)
@logger << "[#{Time.now.strftime('%F %T %z')}] #{message}\n"
end
end
def initialize(environment)
@environment = environment
@settings = Noosfero::Plugin::Settings.new(@environment, SpaminatorPlugin)
@report = SpaminatorPlugin::Report.new({ environment: environment,
total_people: Person.count,
total_comments: Comment.count },
{ without_protection: true })
self.class.initialize_logger(environment)
end
def run
self.class.log("Starting Spaminator scan")
start_time = Time.now
process_all_comments
process_all_people
finish(start_time)
end
protected
def finish(start_time)
finish_report
@settings.last_run = start_time
@settings.save!
self.class.log("Finishing Spaminator scan successfully")
end
# TODO considering run everything always
def on_environment
["profiles.environment_id = ?", @environment.id]
end
def comments_to_process
Comment.joins("JOIN articles ON (comments.source_id = articles.id AND comments.source_type = 'Article') JOIN profiles ON (profiles.id = articles.profile_id)").without_spam.where(on_environment)
end
def people_to_process
Person.visible.non_abusers.where(on_environment)
end
def process_all_comments
self.class.log("Starting to process all comments")
comments = comments_to_process
total = comments.count
pbar = ProgressBar.create(title: "☢ Comments", total: total, format: "%t: |%B| %E") if Rails.env.development?
comments.each do |comment|
begin
process_comment(comment)
rescue
register_fail(:comments, comment)
end
pbar.increment if Rails.env.development?
end
@report.processed_comments = total
pbar.finish if Rails.env.development?
self.class.log("All comments processed")
end
def process_all_people
self.class.log("Starting to process all people")
people = people_to_process
total = people.count
pbar = ProgressBar.create(title: "☢ People", total: total, format: "%t: |%B| %E") if Rails.env.development?
people.find_each do |person|
process_person_by_comments(person)
process_person_by_no_network(person)
pbar.increment if Rails.env.development?
end
@report.processed_people = total
pbar.finish if Rails.env.development?
self.class.log("All people processed")
end
def process_comment(comment)
self.class.log("Processing Comment[#{comment.id.to_s}]")
comment = Comment.find(comment.id)
comment.check_for_spam
@report.spams_by_content += 1 if comment.spam
# TODO several comments with the same content:
# → disable author
# → mark all of them as spam
# TODO check comments that contains URL's
end
def process_person_by_comments(person)
# person is author of more than 2 comments marked as spam
# → mark as spammer
#
self.class.log("Processing Person[#{person.id.to_s}] by comments")
begin
number_of_spam_comments = Comment.spam.where(author_id: person.id).count
if number_of_spam_comments > 2
mark_as_spammer(person)
@report.spammers_by_comments += 1
end
rescue
register_fail(:people, person)
end
end
def process_person_by_no_network(person)
# person who signed up more than one month ago, have no friends and <= 1
# communities
#
# → disable the profile
# ? mark their comments as spam
#
self.class.log("Processing Person[#{person.id.to_s}] by network")
if person.created_at < (Time.now - 1.month) &&
person.friends.count == 0 &&
person.communities.count <= 1
begin
disable_person(person)
@report.spammers_by_no_network += 1
rescue
register_fail(:people, person)
end
Comment.where(author_id: person.id).find_each do |comment|
begin
comment.spam!
@report.spams_by_no_network += 1
rescue
register_fail(:comments, comment)
end
end
end
end
def disable_person(person)
if person.disable
Delayed::Job.enqueue(SpaminatorPlugin::Mailer::Job.new(person, :inactive_person_notification))
end
end
def mark_as_spammer(person)
AbuseComplaint.create!(reported: person).finish
end
def finish_report
puts @report.details
@report.save!
end
def register_fail(kind, failed)
self.class.log("Failed #{kind.to_s.camelize}[#{failed.id.to_s}]")
@report[:failed][kind.to_sym] << failed.id
end
end