2019-05-02 18:17:27 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
class EmailToken < ActiveRecord::Base
|
|
|
|
belongs_to :user
|
|
|
|
|
2014-10-03 23:07:20 -04:00
|
|
|
validates :token, :user_id, :email, presence: true
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2013-02-28 13:54:12 -05:00
|
|
|
before_validation(on: :create) do
|
2013-02-05 14:16:51 -05:00
|
|
|
self.token = EmailToken.generate_token
|
2014-07-14 10:16:24 -04:00
|
|
|
self.email = self.email.downcase if self.email
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
after_create do
|
|
|
|
# Expire the previous tokens
|
2016-05-02 17:15:32 -04:00
|
|
|
EmailToken.where(user_id: self.user_id)
|
|
|
|
.where("id != ?", self.id)
|
|
|
|
.update_all(expired: true)
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.token_length
|
|
|
|
16
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.valid_after
|
2014-07-01 19:08:25 -04:00
|
|
|
SiteSetting.email_token_valid_hours.hours.ago
|
2014-03-04 14:03:04 -05:00
|
|
|
end
|
|
|
|
|
2013-02-22 11:49:48 -05:00
|
|
|
def self.unconfirmed
|
|
|
|
where(confirmed: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.active
|
2013-02-22 15:19:44 -05:00
|
|
|
where(expired: false).where('created_at > ?', valid_after)
|
2013-02-22 11:49:48 -05:00
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
def self.generate_token
|
|
|
|
SecureRandom.hex(EmailToken.token_length)
|
|
|
|
end
|
|
|
|
|
2014-08-25 15:30:52 -04:00
|
|
|
def self.valid_token_format?(token)
|
2016-05-02 17:15:32 -04:00
|
|
|
token.present? && token =~ /\h{#{token.length / 2}}/i
|
2014-08-25 15:30:52 -04:00
|
|
|
end
|
|
|
|
|
2016-03-07 14:40:11 -05:00
|
|
|
def self.atomic_confirm(token)
|
|
|
|
failure = { success: false }
|
|
|
|
return failure unless valid_token_format?(token)
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2016-01-04 11:48:54 -05:00
|
|
|
email_token = confirmable(token)
|
2016-03-07 14:40:11 -05:00
|
|
|
return failure if email_token.blank?
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
user = email_token.user
|
2016-03-07 14:40:11 -05:00
|
|
|
failure[:user] = user
|
2016-12-19 01:15:20 -05:00
|
|
|
row_count = EmailToken.where(confirmed: false, id: email_token.id, expired: false).update_all 'confirmed = true'
|
2016-05-02 17:15:32 -04:00
|
|
|
|
2016-03-07 14:40:11 -05:00
|
|
|
if row_count == 1
|
2016-05-02 17:15:32 -04:00
|
|
|
{ success: true, user: user, email_token: email_token }
|
|
|
|
else
|
|
|
|
failure
|
2016-03-07 14:40:11 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-03 16:03:32 -04:00
|
|
|
def self.confirm(token, skip_reviewable: false)
|
2013-02-05 14:16:51 -05:00
|
|
|
User.transaction do
|
2016-03-07 14:40:11 -05:00
|
|
|
result = atomic_confirm(token)
|
|
|
|
user = result[:user]
|
|
|
|
if result[:success]
|
2013-02-05 14:16:51 -05:00
|
|
|
# If we are activating the user, send the welcome message
|
|
|
|
user.send_welcome_message = !user.active?
|
2016-03-07 14:40:11 -05:00
|
|
|
user.email = result[:email_token].email
|
2019-04-03 16:03:32 -04:00
|
|
|
user.active = true
|
2019-04-10 10:53:52 -04:00
|
|
|
user.custom_fields.delete('activation_reminder')
|
2013-02-05 14:16:51 -05:00
|
|
|
user.save!
|
2019-04-03 16:03:32 -04:00
|
|
|
user.create_reviewable unless skip_reviewable
|
2017-06-14 13:20:18 -04:00
|
|
|
user.set_automatic_groups
|
2021-04-11 22:48:42 -04:00
|
|
|
DiscourseEvent.trigger(:user_confirmed_email, user)
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
2016-01-04 11:48:54 -05:00
|
|
|
|
2016-03-07 14:40:11 -05:00
|
|
|
if user
|
2019-05-13 05:42:05 -04:00
|
|
|
if Invite.redeem_from_email(user.email).present?
|
2021-04-21 05:36:32 -04:00
|
|
|
user.reload
|
2019-05-13 05:42:05 -04:00
|
|
|
end
|
2016-03-07 14:40:11 -05:00
|
|
|
user
|
|
|
|
end
|
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
rescue ActiveRecord::RecordInvalid
|
|
|
|
# If the user's email is already taken, just return nil (failure)
|
|
|
|
end
|
2016-01-04 11:48:54 -05:00
|
|
|
|
|
|
|
def self.confirmable(token)
|
2016-05-02 17:15:32 -04:00
|
|
|
EmailToken.where(token: token)
|
2016-12-19 01:15:20 -05:00
|
|
|
.where(expired: false, confirmed: false)
|
|
|
|
.where("created_at >= ?", EmailToken.valid_after)
|
2016-05-02 17:15:32 -04:00
|
|
|
.includes(:user)
|
|
|
|
.first
|
2016-01-04 11:48:54 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
2013-05-23 22:48:32 -04:00
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: email_tokens
|
|
|
|
#
|
|
|
|
# id :integer not null, primary key
|
|
|
|
# user_id :integer not null
|
2019-01-11 14:29:56 -05:00
|
|
|
# email :string not null
|
|
|
|
# token :string not null
|
2013-05-23 22:48:32 -04:00
|
|
|
# confirmed :boolean default(FALSE), not null
|
|
|
|
# expired :boolean default(FALSE), not null
|
2014-08-27 01:19:25 -04:00
|
|
|
# created_at :datetime not null
|
|
|
|
# updated_at :datetime not null
|
2013-05-23 22:48:32 -04:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
2014-08-22 13:01:44 -04:00
|
|
|
# index_email_tokens_on_token (token) UNIQUE
|
|
|
|
# index_email_tokens_on_user_id (user_id)
|
2013-05-23 22:48:32 -04:00
|
|
|
#
|