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
2013-07-01 14:45:52 -04:00
EmailToken . where ( [ 'user_id = ? and id != ?' , self . user_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
def self . confirm_valid_after
2014-10-10 21:49:37 -04:00
SiteSetting . email_token_grace_period_hours . hours . ago
2013-02-05 14:16:51 -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 )
return token . present? && token =~ / [a-f0-9]{ #{ token . length / 2 } } /i
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
row_count = EmailToken . where ( id : email_token . id , expired : false ) . update_all 'confirmed = true'
if row_count == 1
return { success : true , user : user , email_token : email_token }
end
return failure
end
def self . confirm ( token )
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?
user . active = true
2016-03-07 14:40:11 -05:00
user . email = result [ :email_token ] . email
2013-02-05 14:16:51 -05:00
user . save!
end
2016-01-04 11:48:54 -05:00
2016-03-07 14:40:11 -05:00
if user
return User . find_by ( email : Email . downcase ( user . email ) ) if Invite . redeem_from_email ( user . email ) . present?
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 )
EmailToken . where ( " token = ? and expired = FALSE AND ((NOT confirmed AND created_at >= ?) OR (confirmed AND created_at >= ?)) " , token , EmailToken . valid_after , EmailToken . confirm_valid_after ) . includes ( :user ) . first
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
2016-02-22 18:33:53 -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
#