dcu-devise 1.0.7

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.
Files changed (139) hide show
  1. data/CHANGELOG.rdoc +378 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +260 -0
  4. data/Rakefile +53 -0
  5. data/TODO +2 -0
  6. data/app/controllers/confirmations_controller.rb +33 -0
  7. data/app/controllers/passwords_controller.rb +41 -0
  8. data/app/controllers/registrations_controller.rb +53 -0
  9. data/app/controllers/sessions_controller.rb +44 -0
  10. data/app/controllers/unlocks_controller.rb +41 -0
  11. data/app/models/devise_mailer.rb +68 -0
  12. data/app/views/confirmations/new.html.erb +12 -0
  13. data/app/views/devise_mailer/confirmation_instructions.html.erb +5 -0
  14. data/app/views/devise_mailer/reset_password_instructions.html.erb +8 -0
  15. data/app/views/devise_mailer/unlock_instructions.html.erb +7 -0
  16. data/app/views/passwords/edit.html.erb +16 -0
  17. data/app/views/passwords/new.html.erb +12 -0
  18. data/app/views/registrations/edit.html.erb +25 -0
  19. data/app/views/registrations/new.html.erb +17 -0
  20. data/app/views/sessions/new.html.erb +17 -0
  21. data/app/views/shared/_devise_links.erb +19 -0
  22. data/app/views/unlocks/new.html.erb +12 -0
  23. data/generators/devise/USAGE +5 -0
  24. data/generators/devise/devise_generator.rb +15 -0
  25. data/generators/devise/lib/route_devise.rb +32 -0
  26. data/generators/devise/templates/migration.rb +23 -0
  27. data/generators/devise/templates/model.rb +9 -0
  28. data/generators/devise_install/USAGE +3 -0
  29. data/generators/devise_install/devise_install_generator.rb +15 -0
  30. data/generators/devise_install/templates/README +23 -0
  31. data/generators/devise_install/templates/devise.rb +105 -0
  32. data/generators/devise_views/USAGE +3 -0
  33. data/generators/devise_views/devise_views_generator.rb +21 -0
  34. data/lib/devise.rb +264 -0
  35. data/lib/devise/controllers/helpers.rb +200 -0
  36. data/lib/devise/controllers/internal_helpers.rb +129 -0
  37. data/lib/devise/controllers/url_helpers.rb +41 -0
  38. data/lib/devise/encryptors/authlogic_sha512.rb +21 -0
  39. data/lib/devise/encryptors/base.rb +20 -0
  40. data/lib/devise/encryptors/bcrypt.rb +21 -0
  41. data/lib/devise/encryptors/clearance_sha1.rb +19 -0
  42. data/lib/devise/encryptors/restful_authentication_sha1.rb +22 -0
  43. data/lib/devise/encryptors/sha1.rb +27 -0
  44. data/lib/devise/encryptors/sha512.rb +27 -0
  45. data/lib/devise/failure_app.rb +65 -0
  46. data/lib/devise/hooks/activatable.rb +15 -0
  47. data/lib/devise/hooks/rememberable.rb +32 -0
  48. data/lib/devise/hooks/timeoutable.rb +18 -0
  49. data/lib/devise/hooks/trackable.rb +18 -0
  50. data/lib/devise/locales/en.yml +35 -0
  51. data/lib/devise/mapping.rb +128 -0
  52. data/lib/devise/models.rb +117 -0
  53. data/lib/devise/models/activatable.rb +16 -0
  54. data/lib/devise/models/confirmable.rb +162 -0
  55. data/lib/devise/models/database_authenticatable.rb +144 -0
  56. data/lib/devise/models/http_authenticatable.rb +21 -0
  57. data/lib/devise/models/lockable.rb +150 -0
  58. data/lib/devise/models/recoverable.rb +80 -0
  59. data/lib/devise/models/registerable.rb +8 -0
  60. data/lib/devise/models/rememberable.rb +92 -0
  61. data/lib/devise/models/timeoutable.rb +28 -0
  62. data/lib/devise/models/token_authenticatable.rb +89 -0
  63. data/lib/devise/models/trackable.rb +16 -0
  64. data/lib/devise/models/validatable.rb +39 -0
  65. data/lib/devise/orm/active_record.rb +41 -0
  66. data/lib/devise/orm/data_mapper.rb +83 -0
  67. data/lib/devise/orm/mongo_mapper.rb +47 -0
  68. data/lib/devise/rails.rb +14 -0
  69. data/lib/devise/rails/routes.rb +125 -0
  70. data/lib/devise/rails/warden_compat.rb +25 -0
  71. data/lib/devise/schema.rb +73 -0
  72. data/lib/devise/strategies/base.rb +16 -0
  73. data/lib/devise/strategies/database_authenticatable.rb +36 -0
  74. data/lib/devise/strategies/http_authenticatable.rb +59 -0
  75. data/lib/devise/strategies/rememberable.rb +37 -0
  76. data/lib/devise/strategies/token_authenticatable.rb +37 -0
  77. data/lib/devise/test_helpers.rb +90 -0
  78. data/lib/devise/version.rb +3 -0
  79. data/rails/init.rb +2 -0
  80. data/test/controllers/helpers_test.rb +177 -0
  81. data/test/controllers/internal_helpers_test.rb +55 -0
  82. data/test/controllers/url_helpers_test.rb +47 -0
  83. data/test/devise_test.rb +74 -0
  84. data/test/encryptors_test.rb +31 -0
  85. data/test/failure_app_test.rb +44 -0
  86. data/test/integration/authenticatable_test.rb +271 -0
  87. data/test/integration/confirmable_test.rb +97 -0
  88. data/test/integration/http_authenticatable_test.rb +52 -0
  89. data/test/integration/lockable_test.rb +102 -0
  90. data/test/integration/rack_middleware_test.rb +47 -0
  91. data/test/integration/recoverable_test.rb +141 -0
  92. data/test/integration/registerable_test.rb +144 -0
  93. data/test/integration/rememberable_test.rb +71 -0
  94. data/test/integration/timeoutable_test.rb +68 -0
  95. data/test/integration/token_authenticatable_test.rb +55 -0
  96. data/test/integration/trackable_test.rb +64 -0
  97. data/test/mailers/confirmation_instructions_test.rb +86 -0
  98. data/test/mailers/reset_password_instructions_test.rb +68 -0
  99. data/test/mailers/unlock_instructions_test.rb +62 -0
  100. data/test/mapping_test.rb +148 -0
  101. data/test/models/authenticatable_test.rb +180 -0
  102. data/test/models/confirmable_test.rb +212 -0
  103. data/test/models/lockable_test.rb +202 -0
  104. data/test/models/recoverable_test.rb +138 -0
  105. data/test/models/rememberable_test.rb +135 -0
  106. data/test/models/timeoutable_test.rb +28 -0
  107. data/test/models/token_authenticatable_test.rb +51 -0
  108. data/test/models/trackable_test.rb +5 -0
  109. data/test/models/validatable_test.rb +106 -0
  110. data/test/models_test.rb +70 -0
  111. data/test/orm/active_record.rb +31 -0
  112. data/test/orm/mongo_mapper.rb +20 -0
  113. data/test/rails_app/app/active_record/admin.rb +7 -0
  114. data/test/rails_app/app/active_record/user.rb +7 -0
  115. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  116. data/test/rails_app/app/controllers/application_controller.rb +12 -0
  117. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  118. data/test/rails_app/app/controllers/users_controller.rb +16 -0
  119. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  120. data/test/rails_app/app/mongo_mapper/admin.rb +13 -0
  121. data/test/rails_app/app/mongo_mapper/user.rb +14 -0
  122. data/test/rails_app/config/boot.rb +110 -0
  123. data/test/rails_app/config/environment.rb +42 -0
  124. data/test/rails_app/config/environments/development.rb +17 -0
  125. data/test/rails_app/config/environments/production.rb +28 -0
  126. data/test/rails_app/config/environments/test.rb +28 -0
  127. data/test/rails_app/config/initializers/devise.rb +82 -0
  128. data/test/rails_app/config/initializers/inflections.rb +2 -0
  129. data/test/rails_app/config/initializers/new_rails_defaults.rb +24 -0
  130. data/test/rails_app/config/initializers/session_store.rb +15 -0
  131. data/test/rails_app/config/routes.rb +21 -0
  132. data/test/routes_test.rb +110 -0
  133. data/test/support/assertions_helper.rb +37 -0
  134. data/test/support/integration_tests_helper.rb +71 -0
  135. data/test/support/test_silencer.rb +5 -0
  136. data/test/support/tests_helper.rb +39 -0
  137. data/test/test_helper.rb +21 -0
  138. data/test/test_helpers_test.rb +57 -0
  139. metadata +213 -0
@@ -0,0 +1,16 @@
1
+ require 'devise/hooks/activatable'
2
+
3
+ module Devise
4
+ module Models
5
+ # This module implements the default API required in activatable hook.
6
+ module Activatable
7
+ def active?
8
+ true
9
+ end
10
+
11
+ def inactive_message
12
+ :inactive
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,162 @@
1
+ require 'devise/models/activatable'
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).resend_confirmation! # generates a new token and resent it
31
+ module Confirmable
32
+ include Devise::Models::Activatable
33
+
34
+ def self.included(base)
35
+ base.class_eval do
36
+ extend ClassMethods
37
+
38
+ before_create :generate_confirmation_token, :if => :confirmation_required?
39
+ after_create :send_confirmation_instructions, :if => :confirmation_required?
40
+ end
41
+ end
42
+
43
+ # Confirm a user by setting it's confirmed_at to actual time. If the user
44
+ # is already confirmed, add en error to email field
45
+ def confirm!
46
+ unless_confirmed do
47
+ self.confirmation_token = nil
48
+ self.confirmed_at = Time.now
49
+ save(false)
50
+ end
51
+ end
52
+
53
+ # Verifies whether a user is confirmed or not
54
+ def confirmed?
55
+ !new_record? && !confirmed_at.nil?
56
+ end
57
+
58
+ # Send confirmation instructions by email
59
+ def send_confirmation_instructions
60
+ ::DeviseMailer.deliver_confirmation_instructions(self)
61
+ end
62
+
63
+ # Resend confirmation token. This method does not need to generate a new token.
64
+ def resend_confirmation_token
65
+ unless_confirmed { send_confirmation_instructions }
66
+ end
67
+
68
+ # Overwrites active? from Devise::Models::Activatable for confirmation
69
+ # by verifying whether an user is active to sign in or not. If the user
70
+ # is already confirmed, it should never be blocked. Otherwise we need to
71
+ # calculate if the confirm time has not expired for this user.
72
+ def active?
73
+ super && (confirmed? || confirmation_period_valid?)
74
+ end
75
+
76
+ # The message to be shown if the account is inactive.
77
+ def inactive_message
78
+ !confirmed? ? :unconfirmed : super
79
+ end
80
+
81
+ # If you don't want confirmation to be sent on create, neither a code
82
+ # to be generated, call skip_confirmation!
83
+ def skip_confirmation!
84
+ self.confirmed_at = Time.now
85
+ @skip_confirmation = true
86
+ end
87
+
88
+ protected
89
+
90
+ # Callback to overwrite if confirmation is required or not.
91
+ def confirmation_required?
92
+ !@skip_confirmation
93
+ end
94
+
95
+ # Checks if the confirmation for the user is within the limit time.
96
+ # We do this by calculating if the difference between today and the
97
+ # confirmation sent date does not exceed the confirm in time configured.
98
+ # Confirm_in is a model configuration, must always be an integer value.
99
+ #
100
+ # Example:
101
+ #
102
+ # # confirm_within = 1.day and confirmation_sent_at = today
103
+ # confirmation_period_valid? # returns true
104
+ #
105
+ # # confirm_within = 5.days and confirmation_sent_at = 4.days.ago
106
+ # confirmation_period_valid? # returns true
107
+ #
108
+ # # confirm_within = 5.days and confirmation_sent_at = 5.days.ago
109
+ # confirmation_period_valid? # returns false
110
+ #
111
+ # # confirm_within = 0.days
112
+ # confirmation_period_valid? # will always return false
113
+ #
114
+ def confirmation_period_valid?
115
+ confirmation_sent_at && confirmation_sent_at.utc >= self.class.confirm_within.ago
116
+ end
117
+
118
+ # Checks whether the record is confirmed or not, yielding to the block
119
+ # if it's already confirmed, otherwise adds an error to email.
120
+ def unless_confirmed
121
+ unless confirmed?
122
+ yield
123
+ else
124
+ self.class.add_error_on(self, :email, :already_confirmed)
125
+ false
126
+ end
127
+ end
128
+
129
+ # Generates a new random token for confirmation, and stores the time
130
+ # this token is being generated
131
+ def generate_confirmation_token
132
+ self.confirmed_at = nil
133
+ self.confirmation_token = Devise.friendly_token
134
+ self.confirmation_sent_at = Time.now.utc
135
+ end
136
+
137
+ module ClassMethods
138
+ # Attempt to find a user by it's email. If a record is found, send new
139
+ # confirmation instructions to it. If not user is found, returns a new user
140
+ # with an email not found error.
141
+ # Options must contain the user email
142
+ def send_confirmation_instructions(attributes={})
143
+ confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
144
+ confirmable.resend_confirmation_token unless confirmable.new_record?
145
+ confirmable
146
+ end
147
+
148
+ # Find a user by it's confirmation token and try to confirm it.
149
+ # If no user is found, returns a new user with an error.
150
+ # If the user is already confirmed, create an error for the user
151
+ # Options must have the confirmation_token
152
+ def confirm_by_token(confirmation_token)
153
+ confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
154
+ confirmable.confirm! unless confirmable.new_record?
155
+ confirmable
156
+ end
157
+
158
+ Devise::Models.config(self, :confirm_within)
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,144 @@
1
+ require 'devise/strategies/database_authenticatable'
2
+
3
+ module Devise
4
+ module Models
5
+ # Authenticable Module, responsible for encrypting password and validating
6
+ # authenticity of a user while signing in.
7
+ #
8
+ # Configuration:
9
+ #
10
+ # You can overwrite configuration values by setting in globally in Devise,
11
+ # using devise method or overwriting the respective instance method.
12
+ #
13
+ # pepper: encryption key used for creating encrypted password. Each time
14
+ # password changes, it's gonna be encrypted again, and this key
15
+ # is added to the password and salt to create a secure hash.
16
+ # Always use `rake secret' to generate a new key.
17
+ #
18
+ # stretches: defines how many times the password will be encrypted.
19
+ #
20
+ # encryptor: the encryptor going to be used. By default :sha1.
21
+ #
22
+ # authentication_keys: parameters used for authentication. By default [:email]
23
+ #
24
+ # Examples:
25
+ #
26
+ # User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
27
+ # User.find(1).valid_password?('password123') # returns true/false
28
+ #
29
+ module DatabaseAuthenticatable
30
+ def self.included(base)
31
+ base.class_eval do
32
+ extend ClassMethods
33
+
34
+ attr_reader :password, :current_password
35
+ attr_accessor :password_confirmation
36
+ end
37
+ end
38
+
39
+ # TODO Remove me in next release
40
+ def old_password
41
+ ActiveSupport::Deprecation.warn "old_password is deprecated, please use current_password instead", caller
42
+ @old_password
43
+ end
44
+
45
+ # Regenerates password salt and encrypted password each time password is set,
46
+ # and then trigger any "after_changed_password"-callbacks.
47
+ def password=(new_password)
48
+ @password = new_password
49
+
50
+ if @password.present?
51
+ self.password_salt = self.class.encryptor_class.salt
52
+ self.encrypted_password = password_digest(@password)
53
+ end
54
+ end
55
+
56
+ # Verifies whether an incoming_password (ie from sign in) is the user password.
57
+ def valid_password?(incoming_password)
58
+ password_digest(incoming_password) == self.encrypted_password
59
+ end
60
+
61
+ # Checks if a resource is valid upon authentication.
62
+ def valid_for_authentication?(attributes)
63
+ valid_password?(attributes[:password])
64
+ end
65
+
66
+ # Set password and password confirmation to nil
67
+ def clean_up_passwords
68
+ self.password = self.password_confirmation = nil
69
+ end
70
+
71
+ # Update record attributes when :current_password matches, otherwise returns
72
+ # error on :current_password. It also automatically rejects :password and
73
+ # :password_confirmation if they are blank.
74
+ def update_with_password(params={})
75
+ current_password = params.delete(:current_password)
76
+
77
+ if params[:password].blank?
78
+ params.delete(:password)
79
+ params.delete(:password_confirmation) if params[:password_confirmation].blank?
80
+ end
81
+
82
+ result = if valid_password?(current_password)
83
+ update_attributes(params)
84
+ else
85
+ message = current_password.blank? ? :blank : :invalid
86
+ self.class.add_error_on(self, :current_password, message, false)
87
+ self.attributes = params
88
+ false
89
+ end
90
+
91
+ clean_up_passwords unless result
92
+ result
93
+ end
94
+
95
+ protected
96
+
97
+ # Checks whether a password is needed or not. For validations only.
98
+ # Passwords are always required if it's a new record, or if the password
99
+ # or confirmation are being set somewhere.
100
+ def password_required?
101
+ new_record? || !password.nil? || !password_confirmation.nil?
102
+ end
103
+
104
+ # Digests the password using the configured encryptor.
105
+ def password_digest(password)
106
+ self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
107
+ end
108
+
109
+ module ClassMethods
110
+ Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
111
+
112
+ # Authenticate a user based on configured attribute keys. Returns the
113
+ # authenticated user if it's valid or nil.
114
+ def authenticate(attributes={})
115
+ return unless authentication_keys.all? { |k| attributes[k].present? }
116
+ conditions = attributes.slice(*authentication_keys)
117
+ resource = find_for_authentication(conditions)
118
+ resource if resource.try(:valid_for_authentication?, attributes)
119
+ end
120
+
121
+ # Returns the class for the configured encryptor.
122
+ def encryptor_class
123
+ @encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
124
+ end
125
+
126
+ protected
127
+
128
+ # Find first record based on conditions given (ie by the sign in form).
129
+ # Overwrite to add customized conditions, create a join, or maybe use a
130
+ # namedscope to filter records while authenticating.
131
+ # Example:
132
+ #
133
+ # def self.find_for_authentication(conditions={})
134
+ # conditions[:active] = true
135
+ # find(:first, :conditions => conditions)
136
+ # end
137
+ #
138
+ def find_for_authentication(conditions)
139
+ find(:first, :conditions => conditions)
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,21 @@
1
+ require 'devise/strategies/http_authenticatable'
2
+
3
+ module Devise
4
+ module Models
5
+ # Adds HttpAuthenticatable behavior to your model. It expects that your
6
+ # model class responds to authenticate and authentication_keys methods
7
+ # (which for example are defined in authenticatable).
8
+ module HttpAuthenticatable
9
+ def self.included(base)
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ module ClassMethods
14
+ # Authenticate an user using http.
15
+ def authenticate_with_http(username, password)
16
+ authenticate(authentication_keys.first => username, :password => password)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,150 @@
1
+ require 'devise/models/activatable'
2
+
3
+ module Devise
4
+ module Models
5
+
6
+ # Handles blocking a user access after a certain number of attempts.
7
+ # Lockable accepts two different strategies to unlock a user after it's
8
+ # blocked: email and time. The former will send an email to the user when
9
+ # the lock happens, containing a link to unlock it's account. The second
10
+ # will unlock the user automatically after some configured time (ie 2.hours).
11
+ # It's also possible to setup lockable to use both email and time strategies.
12
+ #
13
+ # Configuration:
14
+ #
15
+ # maximum_attempts: how many attempts should be accepted before blocking the user.
16
+ # unlock_strategy: unlock the user account by :time, :email or :both.
17
+ # unlock_in: the time you want to lock the user after to lock happens. Only
18
+ # available when unlock_strategy is :time or :both.
19
+ #
20
+ module Lockable
21
+ include Devise::Models::Activatable
22
+
23
+ def self.included(base)
24
+ base.class_eval do
25
+ extend ClassMethods
26
+ end
27
+ end
28
+
29
+ # Lock an user setting it's locked_at to actual time.
30
+ def lock_access!
31
+ return true if access_locked?
32
+ self.locked_at = Time.now
33
+
34
+ if self.class.unlock_strategy_enabled?(:email)
35
+ generate_unlock_token
36
+ send_unlock_instructions
37
+ end
38
+
39
+ save(false)
40
+ end
41
+
42
+ # Unlock an user by cleaning locket_at and failed_attempts.
43
+ def unlock_access!
44
+ if_access_locked do
45
+ self.locked_at = nil
46
+ self.failed_attempts = 0
47
+ self.unlock_token = nil
48
+ save(false)
49
+ end
50
+ end
51
+
52
+ # Verifies whether a user is locked or not.
53
+ def access_locked?
54
+ locked_at && !lock_expired?
55
+ end
56
+
57
+ # Send unlock instructions by email
58
+ def send_unlock_instructions
59
+ ::DeviseMailer.deliver_unlock_instructions(self)
60
+ end
61
+
62
+ # Resend the unlock instructions if the user is locked.
63
+ def resend_unlock_token
64
+ if_access_locked { send_unlock_instructions }
65
+ end
66
+
67
+ # Overwrites active? from Devise::Models::Activatable for locking purposes
68
+ # by verifying whether an user is active to sign in or not based on locked?
69
+ def active?
70
+ super && !access_locked?
71
+ end
72
+
73
+ # Overwrites invalid_message from Devise::Models::Authenticatable to define
74
+ # the correct reason for blocking the sign in.
75
+ def inactive_message
76
+ access_locked? ? :locked : super
77
+ end
78
+
79
+ # Overwrites valid_for_authentication? from Devise::Models::Authenticatable
80
+ # for verifying whether an user is allowed to sign in or not. If the user
81
+ # is locked, it should never be allowed.
82
+ def valid_for_authentication?(attributes)
83
+ if result = super
84
+ self.failed_attempts = 0
85
+ else
86
+ self.failed_attempts += 1
87
+ lock_access! if failed_attempts > self.class.maximum_attempts
88
+ end
89
+ save(false) if changed?
90
+ result
91
+ end
92
+
93
+ protected
94
+
95
+ # Generates unlock token
96
+ def generate_unlock_token
97
+ self.unlock_token = Devise.friendly_token
98
+ end
99
+
100
+ # Tells if the lock is expired if :time unlock strategy is active
101
+ def lock_expired?
102
+ if self.class.unlock_strategy_enabled?(:time)
103
+ locked_at && locked_at < self.class.unlock_in.ago
104
+ else
105
+ false
106
+ end
107
+ end
108
+
109
+ # Checks whether the record is locked or not, yielding to the block
110
+ # if it's locked, otherwise adds an error to email.
111
+ def if_access_locked
112
+ if access_locked?
113
+ yield
114
+ else
115
+ self.class.add_error_on(self, :email, :not_locked)
116
+ false
117
+ end
118
+ end
119
+
120
+ module ClassMethods
121
+ # Attempt to find a user by it's email. If a record is found, send new
122
+ # unlock instructions to it. If not user is found, returns a new user
123
+ # with an email not found error.
124
+ # Options must contain the user email
125
+ def send_unlock_instructions(attributes={})
126
+ lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
127
+ lockable.resend_unlock_token unless lockable.new_record?
128
+ lockable
129
+ end
130
+
131
+ # Find a user by it's unlock token and try to unlock it.
132
+ # If no user is found, returns a new user with an error.
133
+ # If the user is not locked, creates an error for the user
134
+ # Options must have the unlock_token
135
+ def unlock_access_by_token(unlock_token)
136
+ lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
137
+ lockable.unlock_access! unless lockable.new_record?
138
+ lockable
139
+ end
140
+
141
+ # Is the unlock enabled for the given unlock strategy?
142
+ def unlock_strategy_enabled?(strategy)
143
+ [:both, strategy].include?(self.unlock_strategy)
144
+ end
145
+
146
+ Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in)
147
+ end
148
+ end
149
+ end
150
+ end