Class: ScreenedEmail

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
ScreeningModel
Defined in:
app/models/screened_email.rb

Overview

A ScreenedEmail record represents an email address that is being watched, typically when creating a new User account. If the email of the signup form (or some other form) matches a ScreenedEmail record, an action can be performed based on the action_type.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ScreeningModel

#action_name=, #record_match!, #set_default_action

Class Method Details

.block(email, opts = {}) ⇒ Object



27
28
29
30
# File 'app/models/screened_email.rb', line 27

def self.block(email, opts = {})
  email = canonical(email)
  find_by_email(email) || create!(opts.slice(:action_type, :ip_address).merge(email: email))
end

.canonical(email) ⇒ Object



20
21
22
23
24
25
# File 'app/models/screened_email.rb', line 20

def self.canonical(email)
  name, domain = email.split("@", 2)
  name = name.gsub(/\+.*/, "")
  name = name.gsub(".", "") if %w[gmail.com googlemail.com].include?(domain.downcase)
  "#{name}@#{domain}".downcase
end

.levenshtein(first, second) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'app/models/screened_email.rb', line 54

def self.levenshtein(first, second)
  matrix = [(0..first.length).to_a]
  (1..second.length).each { |j| matrix << [j] + [0] * (first.length) }

  (1..second.length).each do |i|
    (1..first.length).each do |j|
      if first[j - 1] == second[i - 1]
        matrix[i][j] = matrix[i - 1][j - 1]
      else
        matrix[i][j] = [matrix[i - 1][j], matrix[i][j - 1], matrix[i - 1][j - 1]].min + 1
      end
    end
  end
  matrix.last.last
end

.should_block?(email) ⇒ Boolean

Returns:

  • (Boolean)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'app/models/screened_email.rb', line 32

def self.should_block?(email)
  email = canonical(email)

  screened_emails = ScreenedEmail.order(created_at: :desc).limit(100)

  distances = {}
  screened_emails.each do |se|
    distances[se.email] = levenshtein(se.email.downcase, email.downcase)
  end

  max_distance = SiteSetting.levenshtein_distance_spammer_emails
  screened_email =
    screened_emails
      .select { |se| distances[se.email] <= max_distance }
      .sort { |se| distances[se.email] }
      .first

  screened_email.record_match! if screened_email

  screened_email.try(:action_type) == actions[:block]
end

Instance Method Details

#downcase_emailObject



16
17
18
# File 'app/models/screened_email.rb', line 16

def downcase_email
  self.email = email.downcase
end