1
0
Fork 0
mirror of https://github.com/heartcombo/devise.git synced 2022-11-09 12:18:31 -05:00
heartcombo--devise/lib/devise/models/recoverable.rb

136 lines
5.4 KiB
Ruby

module Devise
module Models
# Recoverable takes care of reseting the user password and send reset instructions.
#
# ==Options
#
# Recoverable adds the following options to devise_for:
#
# * +reset_password_keys+: the keys you want to use when recovering the password for an account
#
# == Examples
#
# # resets the user password and save the record, true if valid passwords are given, otherwise false
# User.find(1).reset_password!('password123', 'password123')
#
# # only resets the user password, without saving the record
# user = User.find(1)
# user.reset_password('password123', 'password123')
#
# # creates a new token and send it with instructions about how to reset the password
# User.find(1).send_reset_password_instructions
#
module Recoverable
extend ActiveSupport::Concern
# Update password saving the record and clearing token. Returns true if
# the passwords are valid and the record was saved, false otherwise.
def reset_password!(new_password, new_password_confirmation)
self.password = new_password
self.password_confirmation = new_password_confirmation
if valid?
clear_reset_password_token
after_password_reset
end
save
end
# Resets reset password token and send reset password instructions by email
def send_reset_password_instructions
generate_reset_password_token! if should_generate_token?
self.devise_mailer.reset_password_instructions(self).deliver
end
# Checks if the reset password token sent is within the limit time.
# We do this by calculating if the difference between today and the
# sending date does not exceed the confirm in time configured.
# Returns true if the resource is not responding to reset_password_sent_at at all.
# reset_password_within is a model configuration, must always be an integer value.
#
# Example:
#
# # reset_password_within = 1.day and reset_password_sent_at = today
# reset_password_period_valid? # returns true
#
# # reset_password_within = 5.days and reset_password_sent_at = 4.days.ago
# reset_password_period_valid? # returns true
#
# # reset_password_within = 5.days and reset_password_sent_at = 5.days.ago
# reset_password_period_valid? # returns false
#
# # reset_password_within = 0.days
# reset_password_period_valid? # will always return false
#
def reset_password_period_valid?
return true unless respond_to?(:reset_password_sent_at)
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
end
protected
def should_generate_token?
reset_password_token.nil? || !reset_password_period_valid?
end
# Generates a new random token for reset password
def generate_reset_password_token
self.reset_password_token = self.class.reset_password_token
self.reset_password_sent_at = Time.now.utc if respond_to?(:reset_password_sent_at=)
self.reset_password_token
end
# Resets the reset password token with and save the record without
# validating
def generate_reset_password_token!
generate_reset_password_token && save(:validate => false)
end
# Removes reset_password token
def clear_reset_password_token
self.reset_password_token = nil
self.reset_password_sent_at = nil if respond_to?(:reset_password_sent_at=)
end
def after_password_reset
end
module ClassMethods
# Attempt to find a user by its email. If a record is found, send new
# password instructions to it. If not user is found, returns a new user
# with an email not found error.
# Attributes must contain the user email
def send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
recoverable.send_reset_password_instructions if recoverable.persisted?
recoverable
end
# Generate a token checking if one does not already exist in the database.
def reset_password_token
generate_token(:reset_password_token)
end
# Attempt to find a user by its reset_password_token to reset its
# password. If a user is found and token is still valid, reset its password and automatically
# try saving the record. If not user is found, returns a new user
# containing an error in reset_password_token attribute.
# Attributes must contain reset_password_token, password and confirmation
def reset_password_by_token(attributes={})
recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
if recoverable.persisted?
if recoverable.reset_password_period_valid?
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
else
recoverable.errors.add(:reset_password_token, :expired)
end
end
recoverable
end
Devise::Models.config(self, :reset_password_keys, :reset_password_within)
end
end
end
end