/emails: add more search options.
Add options to search for invalid emails and emails from restricted domains.
This commit is contained in:
@@ -3,6 +3,10 @@ require 'resolv'
|
|||||||
module EmailValidator
|
module EmailValidator
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
|
# https://www.regular-expressions.info/email.html
|
||||||
|
EMAIL_REGEX = /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/
|
||||||
|
POSTGRES_EMAIL_REGEX = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
|
||||||
|
|
||||||
IGNORE_DOTS = %w[gmail.com]
|
IGNORE_DOTS = %w[gmail.com]
|
||||||
IGNORE_PLUS_ADDRESSING = %w[gmail.com hotmail.com outlook.com live.com]
|
IGNORE_PLUS_ADDRESSING = %w[gmail.com hotmail.com outlook.com live.com]
|
||||||
IGNORE_MINUS_ADDRESSING = %w[yahoo.com]
|
IGNORE_MINUS_ADDRESSING = %w[yahoo.com]
|
||||||
@@ -80,10 +84,17 @@ module EmailValidator
|
|||||||
"#{name}@#{domain}"
|
"#{name}@#{domain}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def nondisposable?(address)
|
def is_valid?(address)
|
||||||
return true if Danbooru.config.email_domain_verification_list.blank?
|
address.match?(EMAIL_REGEX)
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_restricted?(address)
|
||||||
|
return false if Danbooru.config.email_domain_verification_list.blank?
|
||||||
|
|
||||||
domain = Mail::Address.new(address).domain
|
domain = Mail::Address.new(address).domain
|
||||||
domain.in?(Danbooru.config.email_domain_verification_list.to_a)
|
!domain.in?(Danbooru.config.email_domain_verification_list.to_a)
|
||||||
|
rescue Mail::Field::IncompleteParseError
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def undeliverable?(to_address, from_address: Danbooru.config.contact_email, timeout: 3)
|
def undeliverable?(to_address, from_address: Danbooru.config.contact_email, timeout: 3)
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
class EmailAddress < ApplicationRecord
|
class EmailAddress < ApplicationRecord
|
||||||
# https://www.regular-expressions.info/email.html
|
|
||||||
EMAIL_REGEX = /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/
|
|
||||||
|
|
||||||
belongs_to :user, inverse_of: :email_address
|
belongs_to :user, inverse_of: :email_address
|
||||||
|
|
||||||
validates :address, presence: true, confirmation: true, format: { with: EMAIL_REGEX }
|
validates :address, presence: true, confirmation: true, format: { with: EmailValidator::EMAIL_REGEX }
|
||||||
validates :normalized_address, uniqueness: true
|
validates :normalized_address, uniqueness: true
|
||||||
validates :user_id, uniqueness: true
|
validates :user_id, uniqueness: true
|
||||||
validate :validate_deliverable, on: :deliverable
|
validate :validate_deliverable, on: :deliverable
|
||||||
@@ -23,8 +20,49 @@ class EmailAddress < ApplicationRecord
|
|||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def nondisposable?
|
def is_restricted?
|
||||||
EmailValidator.nondisposable?(normalized_address)
|
EmailValidator.is_restricted?(normalized_address)
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_normalized?
|
||||||
|
address == normalized_address
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_valid?
|
||||||
|
EmailValidator.is_valid?(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.restricted(restricted = true)
|
||||||
|
domains = Danbooru.config.email_domain_verification_list
|
||||||
|
domain_regex = domains.map { |domain| Regexp.escape(domain) }.join("|")
|
||||||
|
|
||||||
|
if restricted.to_s.truthy?
|
||||||
|
where_not_regex(:normalized_address, "@(#{domain_regex})$")
|
||||||
|
elsif restricted.to_s.falsy?
|
||||||
|
where_regex(:normalized_address, "@(#{domain_regex})$")
|
||||||
|
else
|
||||||
|
all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.valid(valid = true)
|
||||||
|
if valid.to_s.truthy?
|
||||||
|
where_regex(:address, EmailValidator::POSTGRES_EMAIL_REGEX.to_s)
|
||||||
|
elsif valid.to_s.falsy?
|
||||||
|
where_not_regex(:address, EmailValidator::POSTGRES_EMAIL_REGEX.to_s)
|
||||||
|
else
|
||||||
|
all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.search(params)
|
||||||
|
q = search_attributes(params, :id, :created_at, :updated_at, :user, :address, :normalized_address, :is_verified, :is_deliverable)
|
||||||
|
|
||||||
|
q = q.restricted(params[:is_restricted])
|
||||||
|
q = q.valid(params[:is_valid])
|
||||||
|
q = q.apply_default_order(params)
|
||||||
|
|
||||||
|
q
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_deliverable
|
def validate_deliverable
|
||||||
@@ -34,14 +72,7 @@ class EmailAddress < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update_user
|
def update_user
|
||||||
user.update!(is_verified: is_verified? && nondisposable?)
|
user.update!(is_verified: is_verified? && !is_restricted?)
|
||||||
end
|
|
||||||
|
|
||||||
def self.search(params)
|
|
||||||
q = search_attributes(params, :id, :created_at, :updated_at, :user, :address, :normalized_address, :is_verified, :is_deliverable)
|
|
||||||
q = q.apply_default_order(params)
|
|
||||||
|
|
||||||
q
|
|
||||||
end
|
end
|
||||||
|
|
||||||
concerning :VerificationMethods do
|
concerning :VerificationMethods do
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
<%= fa.input :name, label: "User Name", input_html: { value: params.dig(:search, :user, :name), "data-autocomplete": "user" } %>
|
<%= fa.input :name, label: "User Name", input_html: { value: params.dig(:search, :user, :name), "data-autocomplete": "user" } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= f.input :address_ilike, label: "Address", input_html: { value: params[:search][:address] }, hint: "Use * for wildcard" %>
|
<%= f.input :address_ilike, label: "Address", input_html: { value: params[:search][:address_ilike] }, hint: "Use * for wildcard" %>
|
||||||
<%= f.input :is_verified, label: "Verified?", collection: %w[Yes No], selected: params[:search][:is_verified] %>
|
<%= f.input :normalized_address_ilike, label: "Normalized Address", input_html: { value: params[:search][:normalized_address_ilike] }, hint: "Use * for wildcard" %>
|
||||||
|
<%= f.input :is_valid, label: "Valid?", as: :select, include_blank: true, selected: params[:search][:is_valid] %>
|
||||||
|
<%= f.input :is_verified, label: "Verified?", as: :select, include_blank: true, selected: params[:search][:is_verified] %>
|
||||||
|
<%= f.input :is_restricted, label: "Restricted?", as: :select, include_blank: true, selected: params[:search][:is_restricted] %>
|
||||||
<%= f.submit "Search" %>
|
<%= f.submit "Search" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
@@ -14,8 +17,25 @@
|
|||||||
<% t.column :user do |email| %>
|
<% t.column :user do |email| %>
|
||||||
<%= link_to_user email.user %>
|
<%= link_to_user email.user %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% t.column :address %>
|
<% t.column :address do |email| %>
|
||||||
<% t.column :is_verified, name: "Verified?" do |email| %>
|
<%= link_to email.address, emails_path(search: { address_ilike: email.address }) %>
|
||||||
|
<% end %>
|
||||||
|
<% t.column :normalized_address do |email| %>
|
||||||
|
<% unless email.is_normalized? %>
|
||||||
|
<%= link_to email.normalized_address, emails_path(search: { normalized_address_ilike: email.normalized_address }) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% t.column "Valid?" do |email| %>
|
||||||
|
<% if !email.is_valid? %>
|
||||||
|
<%= link_to "No", emails_path(search: { is_valid: false }) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% t.column "Restricted?" do |email| %>
|
||||||
|
<% if email.is_restricted? %>
|
||||||
|
<%= link_to "Yes", emails_path(search: { is_restricted: true }) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% t.column "Verified?" do |email| %>
|
||||||
<% if email.is_verified? %>
|
<% if email.is_verified? %>
|
||||||
<%= link_to "Yes", emails_path(search: { is_verified: true }) %>
|
<%= link_to "Yes", emails_path(search: { is_verified: true }) %>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|||||||
Reference in New Issue
Block a user