ramon-devise 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +109 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +243 -0
- data/Rakefile +45 -0
- data/TODO +8 -0
- data/app/controllers/confirmations_controller.rb +33 -0
- data/app/controllers/passwords_controller.rb +41 -0
- data/app/controllers/sessions_controller.rb +33 -0
- data/app/models/devise_mailer.rb +53 -0
- data/app/views/confirmations/new.html.erb +16 -0
- data/app/views/devise_mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/devise_mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/passwords/edit.html.erb +20 -0
- data/app/views/passwords/new.html.erb +16 -0
- data/app/views/sessions/new.html.erb +23 -0
- data/generators/devise/USAGE +5 -0
- data/generators/devise/devise_generator.rb +25 -0
- data/generators/devise/lib/route_devise.rb +32 -0
- data/generators/devise/templates/README +22 -0
- data/generators/devise/templates/migration.rb +20 -0
- data/generators/devise/templates/model.rb +5 -0
- data/generators/devise_install/USAGE +3 -0
- data/generators/devise_install/devise_install_generator.rb +9 -0
- data/generators/devise_install/templates/devise.rb +40 -0
- data/generators/devise_views/USAGE +3 -0
- data/generators/devise_views/devise_views_generator.rb +24 -0
- data/init.rb +2 -0
- data/lib/devise.rb +79 -0
- data/lib/devise/controllers/filters.rb +111 -0
- data/lib/devise/controllers/helpers.rb +130 -0
- data/lib/devise/controllers/url_helpers.rb +49 -0
- data/lib/devise/failure.rb +38 -0
- data/lib/devise/hooks/confirmable.rb +11 -0
- data/lib/devise/hooks/rememberable.rb +27 -0
- data/lib/devise/locales/en.yml +18 -0
- data/lib/devise/mapping.rb +120 -0
- data/lib/devise/migrations.rb +51 -0
- data/lib/devise/models.rb +105 -0
- data/lib/devise/models/authenticatable.rb +97 -0
- data/lib/devise/models/confirmable.rb +156 -0
- data/lib/devise/models/recoverable.rb +88 -0
- data/lib/devise/models/rememberable.rb +95 -0
- data/lib/devise/models/validatable.rb +36 -0
- data/lib/devise/rails.rb +17 -0
- data/lib/devise/rails/routes.rb +109 -0
- data/lib/devise/rails/warden_compat.rb +26 -0
- data/lib/devise/strategies/authenticatable.rb +46 -0
- data/lib/devise/strategies/base.rb +24 -0
- data/lib/devise/strategies/rememberable.rb +35 -0
- data/lib/devise/version.rb +3 -0
- data/lib/devise/warden.rb +24 -0
- data/test/controllers/filters_test.rb +103 -0
- data/test/controllers/helpers_test.rb +55 -0
- data/test/controllers/url_helpers_test.rb +47 -0
- data/test/devise_test.rb +72 -0
- data/test/failure_test.rb +34 -0
- data/test/integration/authenticatable_test.rb +187 -0
- data/test/integration/confirmable_test.rb +89 -0
- data/test/integration/recoverable_test.rb +131 -0
- data/test/integration/rememberable_test.rb +65 -0
- data/test/mailers/confirmation_instructions_test.rb +59 -0
- data/test/mailers/reset_password_instructions_test.rb +62 -0
- data/test/mapping_test.rb +101 -0
- data/test/models/authenticatable_test.rb +118 -0
- data/test/models/confirmable_test.rb +237 -0
- data/test/models/recoverable_test.rb +141 -0
- data/test/models/rememberable_test.rb +130 -0
- data/test/models/validatable_test.rb +99 -0
- data/test/models_test.rb +111 -0
- data/test/rails_app/app/controllers/admins_controller.rb +6 -0
- data/test/rails_app/app/controllers/application_controller.rb +10 -0
- data/test/rails_app/app/controllers/home_controller.rb +4 -0
- data/test/rails_app/app/controllers/users_controller.rb +7 -0
- data/test/rails_app/app/helpers/application_helper.rb +3 -0
- data/test/rails_app/app/models/account.rb +3 -0
- data/test/rails_app/app/models/admin.rb +3 -0
- data/test/rails_app/app/models/organizer.rb +3 -0
- data/test/rails_app/app/models/user.rb +3 -0
- data/test/rails_app/config/boot.rb +110 -0
- data/test/rails_app/config/environment.rb +41 -0
- data/test/rails_app/config/environments/development.rb +17 -0
- data/test/rails_app/config/environments/production.rb +28 -0
- data/test/rails_app/config/environments/test.rb +28 -0
- data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
- data/test/rails_app/config/initializers/session_store.rb +15 -0
- data/test/rails_app/config/routes.rb +18 -0
- data/test/routes_test.rb +79 -0
- data/test/support/assertions_helper.rb +22 -0
- data/test/support/integration_tests_helper.rb +66 -0
- data/test/support/model_tests_helper.rb +51 -0
- data/test/test_helper.rb +40 -0
- metadata +154 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Devise
|
2
|
+
# Helpers to migration:
|
3
|
+
#
|
4
|
+
# create_table :accounts do |t|
|
5
|
+
# t.authenticatable
|
6
|
+
# t.confirmable
|
7
|
+
# t.recoverable
|
8
|
+
# t.rememberable
|
9
|
+
# t.timestamps
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# However this method does not add indexes. If you need them, here is the declaration:
|
13
|
+
#
|
14
|
+
# add_index "accounts", ["email"], :name => "email", :unique => true
|
15
|
+
# add_index "accounts", ["confirmation_token"], :name => "confirmation_token", :unique => true
|
16
|
+
# add_index "accounts", ["reset_password_token"], :name => "reset_password_token", :unique => true
|
17
|
+
#
|
18
|
+
module Migrations
|
19
|
+
|
20
|
+
# Creates email, encrypted_password and password_salt.
|
21
|
+
#
|
22
|
+
def authenticatable(options={})
|
23
|
+
null = options[:null] || false
|
24
|
+
string :email, :limit => 100, :null => null
|
25
|
+
string :encrypted_password, :limit => 40, :null => null
|
26
|
+
string :password_salt, :limit => 20, :null => null
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates confirmation_token, confirmed_at and confirmation_sent_at.
|
30
|
+
#
|
31
|
+
def confirmable
|
32
|
+
string :confirmation_token, :limit => 20
|
33
|
+
datetime :confirmed_at
|
34
|
+
datetime :confirmation_sent_at
|
35
|
+
end
|
36
|
+
|
37
|
+
# Creates reset_password_token.
|
38
|
+
#
|
39
|
+
def recoverable
|
40
|
+
string :reset_password_token, :limit => 20
|
41
|
+
end
|
42
|
+
|
43
|
+
# Creates remember_token and remember_created_at.
|
44
|
+
#
|
45
|
+
def rememberable
|
46
|
+
string :remember_token, :limit => 20
|
47
|
+
datetime :remember_created_at
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
# Creates configuration values for Devise and for the given module.
|
4
|
+
#
|
5
|
+
# Devise::Models.config(Devise::Authenticable, :stretches, 10)
|
6
|
+
#
|
7
|
+
# The line above creates:
|
8
|
+
#
|
9
|
+
# 1) An accessor called Devise.stretches, which value is used by default;
|
10
|
+
#
|
11
|
+
# 2) Some class methods for your model Model.stretches and Model.stretches=
|
12
|
+
# which have higher priority than Devise.stretches;
|
13
|
+
#
|
14
|
+
# 3) And an instance method stretches.
|
15
|
+
#
|
16
|
+
# To add the class methods you need to have a module ClassMethods defined
|
17
|
+
# inside the given class.
|
18
|
+
#
|
19
|
+
def self.config(mod, accessor, default=nil) #:nodoc:
|
20
|
+
Devise.send :"#{accessor}=", default
|
21
|
+
|
22
|
+
mod.class_eval <<-METHOD, __FILE__, __LINE__
|
23
|
+
def #{accessor}
|
24
|
+
self.class.#{accessor}
|
25
|
+
end
|
26
|
+
METHOD
|
27
|
+
|
28
|
+
mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
|
29
|
+
def #{accessor}
|
30
|
+
if defined?(@#{accessor})
|
31
|
+
@#{accessor}
|
32
|
+
elsif superclass.respond_to?(:#{accessor})
|
33
|
+
superclass.#{accessor}
|
34
|
+
else
|
35
|
+
Devise.#{accessor}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def #{accessor}=(value)
|
40
|
+
@#{accessor} = value
|
41
|
+
end
|
42
|
+
METHOD
|
43
|
+
end
|
44
|
+
|
45
|
+
# Shortcut method for including all devise modules inside your model.
|
46
|
+
# You can give some extra options while declaring devise in your model:
|
47
|
+
#
|
48
|
+
# * except: convenient option that allows you to add all devise modules,
|
49
|
+
# removing only the modules you setup here:
|
50
|
+
#
|
51
|
+
# devise :all, :except => :rememberable
|
52
|
+
#
|
53
|
+
# You can also give the following configuration values in a hash: :pepper,
|
54
|
+
# :stretches, :confirm_within and :remember_for. Please check your Devise
|
55
|
+
# initialiazer for a complete description on those values.
|
56
|
+
#
|
57
|
+
# Examples:
|
58
|
+
#
|
59
|
+
# # include only authenticatable module (default)
|
60
|
+
# devise
|
61
|
+
#
|
62
|
+
# # include authenticatable + confirmable modules
|
63
|
+
# devise :confirmable
|
64
|
+
#
|
65
|
+
# # include authenticatable + recoverable modules
|
66
|
+
# devise :recoverable
|
67
|
+
#
|
68
|
+
# # include authenticatable + rememberable modules
|
69
|
+
# devise :rememberable
|
70
|
+
#
|
71
|
+
# # include authenticatable + validatable modules
|
72
|
+
# devise :validatable
|
73
|
+
#
|
74
|
+
# # include authenticatable + confirmable + recoverable + rememberable + validatable
|
75
|
+
# devise :confirmable, :recoverable, :rememberable, :validatable
|
76
|
+
#
|
77
|
+
# # shortcut to include all modules (same as above)
|
78
|
+
# devise :all
|
79
|
+
#
|
80
|
+
# # include all except recoverable
|
81
|
+
# devise :all, :except => :recoverable
|
82
|
+
#
|
83
|
+
def devise(*modules)
|
84
|
+
options = modules.extract_options!
|
85
|
+
|
86
|
+
modules = Devise::ALL if modules.include?(:all)
|
87
|
+
modules -= Array(options.delete(:except))
|
88
|
+
modules = [:authenticatable] | modules
|
89
|
+
|
90
|
+
modules.each do |m|
|
91
|
+
devise_modules << m.to_sym
|
92
|
+
include Devise::Models.const_get(m.to_s.classify)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Convert new keys to methods which overwrites Devise defaults
|
96
|
+
options.each { |key, value| send(:"#{key}=", value) }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Stores all modules included inside the model, so we are able to verify
|
100
|
+
# which routes are needed.
|
101
|
+
def devise_modules
|
102
|
+
@devise_modules ||= []
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'devise/strategies/authenticatable'
|
3
|
+
|
4
|
+
module Devise
|
5
|
+
module Models
|
6
|
+
|
7
|
+
# Authenticable Module, responsible for encrypting password and validating
|
8
|
+
# authenticity of a user while signing in.
|
9
|
+
#
|
10
|
+
# Configuration:
|
11
|
+
#
|
12
|
+
# You can overwrite configuration values by setting in globally in Devise,
|
13
|
+
# using devise method or overwriting the respective instance method.
|
14
|
+
#
|
15
|
+
# pepper: encryption key used for creating encrypted password. Each time
|
16
|
+
# password changes, it's gonna be encrypted again, and this key
|
17
|
+
# is added to the password and salt to create a secure hash.
|
18
|
+
# Always use `rake secret' to generate a new key.
|
19
|
+
#
|
20
|
+
# stretches: defines how many times the password will be encrypted.
|
21
|
+
#
|
22
|
+
# Examples:
|
23
|
+
#
|
24
|
+
# User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
|
25
|
+
# User.find(1).valid_password?('password123') # returns true/false
|
26
|
+
#
|
27
|
+
module Authenticatable
|
28
|
+
def self.included(base)
|
29
|
+
base.class_eval do
|
30
|
+
extend ClassMethods
|
31
|
+
|
32
|
+
attr_reader :password
|
33
|
+
attr_accessor :password_confirmation
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Regenerates password salt and encrypted password each time password is
|
38
|
+
# setted.
|
39
|
+
def password=(new_password)
|
40
|
+
@password = new_password
|
41
|
+
self.password_salt = friendly_token
|
42
|
+
self.encrypted_password = password_digest(@password)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Verifies whether an incoming_password (ie from login) is the user
|
46
|
+
# password.
|
47
|
+
def valid_password?(incoming_password)
|
48
|
+
password_digest(incoming_password) == encrypted_password
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# Gererates a default password digest based on salt, pepper and the
|
54
|
+
# incoming password.
|
55
|
+
def password_digest(password_to_digest)
|
56
|
+
digest = pepper
|
57
|
+
stretches.times { digest = secure_digest(password_salt, digest, password_to_digest, pepper) }
|
58
|
+
digest
|
59
|
+
end
|
60
|
+
|
61
|
+
# Generate a SHA1 digest joining args. Generated token is something like
|
62
|
+
#
|
63
|
+
# --arg1--arg2--arg3--argN--
|
64
|
+
def secure_digest(*tokens)
|
65
|
+
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
66
|
+
end
|
67
|
+
|
68
|
+
# Generate a friendly string randomically to be used as token.
|
69
|
+
def friendly_token
|
70
|
+
ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
|
71
|
+
end
|
72
|
+
|
73
|
+
module ClassMethods
|
74
|
+
# Authenticate a user based on email and password. Returns the
|
75
|
+
# authenticated user if it's valid or nil.
|
76
|
+
# Attributes are :email and :password
|
77
|
+
def authenticate(attributes={})
|
78
|
+
authenticatable = find_by_email(attributes[:email])
|
79
|
+
authenticatable if authenticatable.try(:valid_password?, attributes[:password])
|
80
|
+
end
|
81
|
+
|
82
|
+
# Attempt to find a user by it's email. If not user is found, returns a
|
83
|
+
# new user with an email not found error.
|
84
|
+
def find_or_initialize_with_error_by_email(email)
|
85
|
+
perishable = find_or_initialize_by_email(email)
|
86
|
+
if perishable.new_record?
|
87
|
+
perishable.errors.add(:email, :not_found, :default => 'not found')
|
88
|
+
end
|
89
|
+
perishable
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
Devise::Models.config(self, :pepper)
|
94
|
+
Devise::Models.config(self, :stretches, 10)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'devise/hooks/confirmable'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module Models
|
5
|
+
|
6
|
+
# Confirmable is responsible to verify if an account is already confirmed to
|
7
|
+
# sign in, and to send emails with confirmation instructions.
|
8
|
+
# Confirmation instructions are sent to the user email after creating a
|
9
|
+
# record, after updating it's email and also when manually requested by
|
10
|
+
# a new confirmation instruction request.
|
11
|
+
# Whenever the user update it's email, his account is automatically unconfirmed,
|
12
|
+
# it means it won't be able to sign in again without confirming the account
|
13
|
+
# again through the email that was sent.
|
14
|
+
#
|
15
|
+
# Configuration:
|
16
|
+
#
|
17
|
+
# confirm_within: the time you want the user will have to confirm it's account
|
18
|
+
# without blocking his access. When confirm_within is zero, the
|
19
|
+
# user won't be able to sign in without confirming. You can
|
20
|
+
# use this to let your user access some features of your
|
21
|
+
# application without confirming the account, but blocking it
|
22
|
+
# after a certain period (ie 7 days). By default confirm_within is
|
23
|
+
# zero, it means users always have to confirm to sign in.
|
24
|
+
#
|
25
|
+
# Examples:
|
26
|
+
#
|
27
|
+
# User.find(1).confirm! # returns true unless it's already confirmed
|
28
|
+
# User.find(1).confirmed? # true/false
|
29
|
+
# User.find(1).send_confirmation_instructions # manually send instructions
|
30
|
+
# User.find(1).reset_confirmation! # reset confirmation status and send instructions
|
31
|
+
module Confirmable
|
32
|
+
|
33
|
+
def self.included(base)
|
34
|
+
base.class_eval do
|
35
|
+
extend ClassMethods
|
36
|
+
|
37
|
+
before_create :generate_confirmation_token
|
38
|
+
after_create :send_confirmation_instructions
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
43
|
+
# is already confirmed, add en error to email field
|
44
|
+
def confirm!
|
45
|
+
unless_confirmed do
|
46
|
+
self.confirmation_token = nil
|
47
|
+
self.confirmed_at = Time.now
|
48
|
+
save(false)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Verifies whether a user is confirmed or not
|
53
|
+
def confirmed?
|
54
|
+
!new_record? && confirmed_at?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Send confirmation instructions by email
|
58
|
+
def send_confirmation_instructions
|
59
|
+
::DeviseMailer.deliver_confirmation_instructions(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Remove confirmation date and send confirmation instructions, to ensure
|
63
|
+
# after sending these instructions the user won't be able to sign in without
|
64
|
+
# confirming it's account
|
65
|
+
def reset_confirmation!
|
66
|
+
unless_confirmed do
|
67
|
+
generate_confirmation_token
|
68
|
+
save(false)
|
69
|
+
send_confirmation_instructions
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Verify whether a user is active to sign in or not. If the user is
|
74
|
+
# already confirmed, it should never be blocked. Otherwise we need to
|
75
|
+
# calculate if the confirm time has not expired for this user, in other
|
76
|
+
# words, if the confirmation is still valid.
|
77
|
+
def active?
|
78
|
+
confirmed? || confirmation_period_valid?
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Checks if the confirmation for the user is within the limit time.
|
84
|
+
# We do this by calculating if the difference between today and the
|
85
|
+
# confirmation sent date does not exceed the confirm in time configured.
|
86
|
+
# Confirm_in is a model configuration, must always be an integer value.
|
87
|
+
#
|
88
|
+
# Example:
|
89
|
+
#
|
90
|
+
# # confirm_within = 1.day and confirmation_sent_at = today
|
91
|
+
# confirmation_period_valid? # returns true
|
92
|
+
#
|
93
|
+
# # confirm_within = 5.days and confirmation_sent_at = 4.days.ago
|
94
|
+
# confirmation_period_valid? # returns true
|
95
|
+
#
|
96
|
+
# # confirm_within = 5.days and confirmation_sent_at = 5.days.ago
|
97
|
+
# confirmation_period_valid? # returns false
|
98
|
+
#
|
99
|
+
# # confirm_within = 0.days
|
100
|
+
# confirmation_period_valid? # will always return false
|
101
|
+
#
|
102
|
+
def confirmation_period_valid?
|
103
|
+
confirmation_sent_at? &&
|
104
|
+
(Time.now.utc - confirmation_sent_at.utc) < confirm_within
|
105
|
+
end
|
106
|
+
|
107
|
+
# Checks whether the record is confirmed or not, yielding to the block
|
108
|
+
# if it's already confirmed, otherwise adds an error to email.
|
109
|
+
def unless_confirmed
|
110
|
+
unless confirmed?
|
111
|
+
yield
|
112
|
+
else
|
113
|
+
errors.add(:email, :already_confirmed, :default => 'already confirmed')
|
114
|
+
false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Generates a new random token for confirmation, and stores the time
|
119
|
+
# this token is being generated
|
120
|
+
def generate_confirmation_token
|
121
|
+
self.confirmed_at = nil
|
122
|
+
self.confirmation_token = friendly_token
|
123
|
+
self.confirmation_sent_at = Time.now.utc
|
124
|
+
end
|
125
|
+
|
126
|
+
module ClassMethods
|
127
|
+
|
128
|
+
# Attempt to find a user by it's email. If a record is found, send new
|
129
|
+
# confirmation instructions to it. If not user is found, returns a new user
|
130
|
+
# with an email not found error.
|
131
|
+
# Options must contain the user email
|
132
|
+
def send_confirmation_instructions(attributes={})
|
133
|
+
confirmable = find_or_initialize_with_error_by_email(attributes[:email])
|
134
|
+
confirmable.reset_confirmation! unless confirmable.new_record?
|
135
|
+
confirmable
|
136
|
+
end
|
137
|
+
|
138
|
+
# Find a user by it's confirmation token and try to confirm it.
|
139
|
+
# If no user is found, returns a new user with an error.
|
140
|
+
# If the user is already confirmed, create an error for the user
|
141
|
+
# Options must have the confirmation_token
|
142
|
+
def confirm!(attributes={})
|
143
|
+
confirmable = find_or_initialize_by_confirmation_token(attributes[:confirmation_token])
|
144
|
+
if confirmable.new_record?
|
145
|
+
confirmable.errors.add(:confirmation_token, :invalid)
|
146
|
+
else
|
147
|
+
confirmable.confirm!
|
148
|
+
end
|
149
|
+
confirmable
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
Devise::Models.config(self, :confirm_within, 0.days)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
|
4
|
+
# Recoverable takes care of reseting the user password and send reset instructions
|
5
|
+
# Examples:
|
6
|
+
#
|
7
|
+
# # resets the user password and save the record, true if valid passwords are given, otherwise false
|
8
|
+
# User.find(1).reset_password!('password123', 'password123')
|
9
|
+
# # only resets the user password, without saving the record
|
10
|
+
# user = User.find(1)
|
11
|
+
# user.reset_password('password123', 'password123')
|
12
|
+
# # creates a new token and send it with instructions about how to reset the password
|
13
|
+
# User.find(1).send_reset_password_instructions
|
14
|
+
module Recoverable
|
15
|
+
def self.included(base)
|
16
|
+
base.class_eval do
|
17
|
+
extend ClassMethods
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Update password
|
22
|
+
def reset_password(new_password, new_password_confirmation)
|
23
|
+
self.password = new_password
|
24
|
+
self.password_confirmation = new_password_confirmation
|
25
|
+
end
|
26
|
+
|
27
|
+
# Update password saving the record and clearing token. Returns true if
|
28
|
+
# the passwords are valid and the record was saved, false otherwise.
|
29
|
+
def reset_password!(new_password, new_password_confirmation)
|
30
|
+
reset_password(new_password, new_password_confirmation)
|
31
|
+
clear_reset_password_token if valid?
|
32
|
+
save
|
33
|
+
end
|
34
|
+
|
35
|
+
# Resets reset password token and send reset password instructions by email
|
36
|
+
def send_reset_password_instructions
|
37
|
+
generate_reset_password_token!
|
38
|
+
::DeviseMailer.deliver_reset_password_instructions(self)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
# Generates a new random token for reset password
|
44
|
+
def generate_reset_password_token
|
45
|
+
self.reset_password_token = friendly_token
|
46
|
+
end
|
47
|
+
|
48
|
+
# Resets the reset password token with and save the record without
|
49
|
+
# validating
|
50
|
+
def generate_reset_password_token!
|
51
|
+
generate_reset_password_token && save(false)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Removes reset_password token
|
55
|
+
def clear_reset_password_token
|
56
|
+
self.reset_password_token = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
|
61
|
+
# Attempt to find a user by it's email. If a record is found, send new
|
62
|
+
# password instructions to it. If not user is found, returns a new user
|
63
|
+
# with an email not found error.
|
64
|
+
# Attributes must contain the user email
|
65
|
+
def send_reset_password_instructions(attributes={})
|
66
|
+
recoverable = find_or_initialize_with_error_by_email(attributes[:email])
|
67
|
+
recoverable.send_reset_password_instructions unless recoverable.new_record?
|
68
|
+
recoverable
|
69
|
+
end
|
70
|
+
|
71
|
+
# Attempt to find a user by it's reset_password_token to reset it's
|
72
|
+
# password. If a user is found, reset it's password and automatically
|
73
|
+
# try saving the record. If not user is found, returns a new user
|
74
|
+
# containing an error in reset_password_token attribute.
|
75
|
+
# Attributes must contain reset_password_token, password and confirmation
|
76
|
+
def reset_password!(attributes={})
|
77
|
+
recoverable = find_or_initialize_by_reset_password_token(attributes[:reset_password_token])
|
78
|
+
if recoverable.new_record?
|
79
|
+
recoverable.errors.add(:reset_password_token, :invalid)
|
80
|
+
else
|
81
|
+
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
|
82
|
+
end
|
83
|
+
recoverable
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|