devise 4.2.0 → 4.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of devise might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +9 -4
- data/CHANGELOG.md +14 -1
- data/CONTRIBUTING.md +68 -28
- data/Gemfile.lock +69 -74
- data/README.md +10 -6
- data/app/controllers/devise/registrations_controller.rb +1 -0
- data/app/mailers/devise/mailer.rb +4 -0
- data/app/views/devise/mailer/email_changed.html.erb +7 -0
- data/config/locales/en.yml +2 -0
- data/gemfiles/Gemfile.rails-4.1-stable.lock +65 -68
- data/gemfiles/Gemfile.rails-4.2-stable.lock +65 -70
- data/lib/devise.rb +5 -1
- data/lib/devise/controllers/store_location.rb +1 -1
- data/lib/devise/failure_app.rb +12 -12
- data/lib/devise/hooks/lockable.rb +4 -1
- data/lib/devise/mailers/helpers.rb +4 -3
- data/lib/devise/models.rb +1 -1
- data/lib/devise/models/confirmable.rb +14 -2
- data/lib/devise/models/database_authenticatable.rb +16 -1
- data/lib/devise/models/recoverable.rb +8 -4
- data/lib/devise/models/rememberable.rb +1 -1
- data/lib/devise/rails/routes.rb +1 -1
- data/lib/devise/test/controller_helpers.rb +1 -1
- data/lib/devise/test_helpers.rb +1 -1
- data/lib/devise/version.rb +1 -1
- data/lib/generators/templates/controllers/registrations_controller.rb +2 -2
- data/lib/generators/templates/controllers/sessions_controller.rb +1 -1
- data/lib/generators/templates/devise.rb +4 -1
- data/lib/generators/templates/markerb/email_changed.markerb +7 -0
- data/lib/generators/templates/markerb/password_change.markerb +2 -2
- data/test/controllers/helpers_test.rb +3 -3
- data/test/integration/authenticatable_test.rb +1 -1
- data/test/mailers/email_changed_test.rb +130 -0
- data/test/mailers/mailer_test.rb +18 -0
- data/test/models/confirmable_test.rb +17 -0
- data/test/models/database_authenticatable_test.rb +13 -1
- data/test/models/recoverable_test.rb +11 -1
- data/test/omniauth/config_test.rb +9 -7
- metadata +9 -3
data/lib/devise.rb
CHANGED
@@ -153,7 +153,11 @@ module Devise
|
|
153
153
|
mattr_accessor :pepper
|
154
154
|
@@pepper = nil
|
155
155
|
|
156
|
-
# Used to
|
156
|
+
# Used to send notification to the original user email when their email is changed.
|
157
|
+
mattr_accessor :send_email_changed_notification
|
158
|
+
@@send_email_changed_notification = false
|
159
|
+
|
160
|
+
# Used to enable sending notification to user when their password is changed.
|
157
161
|
mattr_accessor :send_password_change_notification
|
158
162
|
@@send_password_change_notification = false
|
159
163
|
|
@@ -29,7 +29,7 @@ module Devise
|
|
29
29
|
# Example:
|
30
30
|
#
|
31
31
|
# store_location_for(:user, dashboard_path)
|
32
|
-
# redirect_to
|
32
|
+
# redirect_to user_facebook_omniauth_authorize_path
|
33
33
|
#
|
34
34
|
def store_location_for(resource_or_scope, location)
|
35
35
|
session_key = stored_location_key_for(resource_or_scope)
|
data/lib/devise/failure_app.rb
CHANGED
@@ -2,9 +2,9 @@ require "action_controller/metal"
|
|
2
2
|
|
3
3
|
module Devise
|
4
4
|
# Failure application that will be called every time :warden is thrown from
|
5
|
-
# any strategy or hook.
|
6
|
-
# page based on current scope and mapping. If no scope is given,
|
7
|
-
# to the default_url.
|
5
|
+
# any strategy or hook. It is responsible for redirecting the user to the sign
|
6
|
+
# in page based on current scope and mapping. If no scope is given, it
|
7
|
+
# redirects to the default_url.
|
8
8
|
class FailureApp < ActionController::Metal
|
9
9
|
include ActionController::UrlFor
|
10
10
|
include ActionController::Redirecting
|
@@ -160,12 +160,12 @@ module Devise
|
|
160
160
|
%w(html */*).include? request_format.to_s
|
161
161
|
end
|
162
162
|
|
163
|
-
# Choose whether we should respond in
|
163
|
+
# Choose whether we should respond in an HTTP authentication fashion,
|
164
164
|
# including 401 and optional headers.
|
165
165
|
#
|
166
|
-
# This method allows the user to explicitly disable
|
167
|
-
# on
|
168
|
-
# handling the errors on their own. This is useful in case your
|
166
|
+
# This method allows the user to explicitly disable HTTP authentication
|
167
|
+
# on AJAX requests in case they want to redirect on failures instead of
|
168
|
+
# handling the errors on their own. This is useful in case your AJAX API
|
169
169
|
# is the same as your public API and uses a format like JSON (so you
|
170
170
|
# cannot mark JSON as a navigational format).
|
171
171
|
def http_auth?
|
@@ -176,7 +176,7 @@ module Devise
|
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
179
|
-
# It
|
179
|
+
# It doesn't make sense to send authenticate headers in AJAX requests
|
180
180
|
# or if the user disabled them.
|
181
181
|
def http_auth_header?
|
182
182
|
scope_class.http_authenticatable && !request.xhr?
|
@@ -225,10 +225,10 @@ module Devise
|
|
225
225
|
warden_options[:attempted_path]
|
226
226
|
end
|
227
227
|
|
228
|
-
# Stores requested
|
229
|
-
# scoped session provided by warden here, since the user is not
|
230
|
-
# yet, but we still need to store the
|
231
|
-
# would never use the same
|
228
|
+
# Stores requested URI to redirect the user after signing in. We can't use
|
229
|
+
# the scoped session provided by warden here, since the user is not
|
230
|
+
# authenticated yet, but we still need to store the URI based on scope, so
|
231
|
+
# different scopes would never use the same URI to redirect.
|
232
232
|
def store_location!
|
233
233
|
store_location_for(scope, attempted_path) if request.get? && !http_auth?
|
234
234
|
end
|
@@ -2,6 +2,9 @@
|
|
2
2
|
# This is only triggered when the user is explicitly set (with set_user)
|
3
3
|
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
4
4
|
if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
|
5
|
-
|
5
|
+
unless record.failed_attempts.to_i.zero?
|
6
|
+
record.failed_attempts = 0
|
7
|
+
record.save(validate: false)
|
8
|
+
end
|
6
9
|
end
|
7
10
|
end
|
@@ -5,15 +5,16 @@ module Devise
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
include Devise::Controllers::ScopedViews
|
8
|
-
attr_reader :scope_name, :resource
|
9
8
|
end
|
10
9
|
|
11
10
|
protected
|
12
11
|
|
12
|
+
attr_reader :scope_name, :resource
|
13
|
+
|
13
14
|
# Configure default email options
|
14
|
-
def devise_mail(record, action, opts={})
|
15
|
+
def devise_mail(record, action, opts = {}, &block)
|
15
16
|
initialize_from_record(record)
|
16
|
-
mail headers_for(action, opts)
|
17
|
+
mail headers_for(action, opts), &block
|
17
18
|
end
|
18
19
|
|
19
20
|
def initialize_from_record(record)
|
data/lib/devise/models.rb
CHANGED
@@ -12,7 +12,7 @@ module Devise
|
|
12
12
|
|
13
13
|
# Creates configuration values for Devise and for the given module.
|
14
14
|
#
|
15
|
-
# Devise::Models.config(Devise::DatabaseAuthenticatable, :stretches)
|
15
|
+
# Devise::Models.config(Devise::Models::DatabaseAuthenticatable, :stretches)
|
16
16
|
#
|
17
17
|
# The line above creates:
|
18
18
|
#
|
@@ -26,7 +26,9 @@ module Devise
|
|
26
26
|
# initial account confirmation) to be applied. Requires additional unconfirmed_email
|
27
27
|
# db field to be set up (t.reconfirmable in migrations). Until confirmed, new email is
|
28
28
|
# stored in unconfirmed email column, and copied to email column on successful
|
29
|
-
# confirmation.
|
29
|
+
# confirmation. Also, when used in conjunction with `send_email_changed_notification`,
|
30
|
+
# the notification is sent to the original email when the change is requested,
|
31
|
+
# not when the unconfirmed email is confirmed.
|
30
32
|
# * +confirm_within+: the time before a sent confirmation token becomes invalid.
|
31
33
|
# You can use this to force the user to confirm within a set period of time.
|
32
34
|
# Confirmable will not generate a new token if a repeat confirmation is requested
|
@@ -223,7 +225,7 @@ module Devise
|
|
223
225
|
# confirmation_period_expired? # will always return false
|
224
226
|
#
|
225
227
|
def confirmation_period_expired?
|
226
|
-
self.class.confirm_within && self.confirmation_sent_at && (Time.now > self.confirmation_sent_at + self.class.confirm_within)
|
228
|
+
self.class.confirm_within && self.confirmation_sent_at && (Time.now.utc > self.confirmation_sent_at.utc + self.class.confirm_within)
|
227
229
|
end
|
228
230
|
|
229
231
|
# Checks whether the record requires any confirmation.
|
@@ -277,6 +279,16 @@ module Devise
|
|
277
279
|
confirmation_required? && !@skip_confirmation_notification && self.email.present?
|
278
280
|
end
|
279
281
|
|
282
|
+
# With reconfirmable, notify the original email when the user first
|
283
|
+
# requests the email change, instead of when the change is confirmed.
|
284
|
+
def send_email_changed_notification?
|
285
|
+
if self.class.reconfirmable
|
286
|
+
self.class.send_email_changed_notification && reconfirmation_required?
|
287
|
+
else
|
288
|
+
super
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
280
292
|
# A callback initiated after successfully confirming. This can be
|
281
293
|
# used to insert your own logic that is only run after the user successfully
|
282
294
|
# confirms.
|
@@ -14,6 +14,10 @@ module Devise
|
|
14
14
|
#
|
15
15
|
# * +stretches+: the cost given to bcrypt.
|
16
16
|
#
|
17
|
+
# * +send_email_changed_notification+: notify original email when it changes.
|
18
|
+
#
|
19
|
+
# * +send_password_change_notification+: notify email when password changes.
|
20
|
+
#
|
17
21
|
# == Examples
|
18
22
|
#
|
19
23
|
# User.find(1).valid_password?('password123') # returns true/false
|
@@ -22,6 +26,7 @@ module Devise
|
|
22
26
|
extend ActiveSupport::Concern
|
23
27
|
|
24
28
|
included do
|
29
|
+
after_update :send_email_changed_notification, if: :send_email_changed_notification?
|
25
30
|
after_update :send_password_change_notification, if: :send_password_change_notification?
|
26
31
|
|
27
32
|
attr_reader :password, :current_password
|
@@ -132,6 +137,12 @@ module Devise
|
|
132
137
|
encrypted_password[0,29] if encrypted_password
|
133
138
|
end
|
134
139
|
|
140
|
+
# Send notification to user when email changes.
|
141
|
+
def send_email_changed_notification
|
142
|
+
send_devise_notification(:email_changed, to: email_was)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Send notification to user when password changes.
|
135
146
|
def send_password_change_notification
|
136
147
|
send_devise_notification(:password_change)
|
137
148
|
end
|
@@ -147,12 +158,16 @@ module Devise
|
|
147
158
|
Devise::Encryptor.digest(self.class, password)
|
148
159
|
end
|
149
160
|
|
161
|
+
def send_email_changed_notification?
|
162
|
+
self.class.send_email_changed_notification && email_changed?
|
163
|
+
end
|
164
|
+
|
150
165
|
def send_password_change_notification?
|
151
166
|
self.class.send_password_change_notification && encrypted_password_changed?
|
152
167
|
end
|
153
168
|
|
154
169
|
module ClassMethods
|
155
|
-
Devise::Models.config(self, :pepper, :stretches, :send_password_change_notification)
|
170
|
+
Devise::Models.config(self, :pepper, :stretches, :send_email_changed_notification, :send_password_change_notification)
|
156
171
|
|
157
172
|
# We assume this method already gets the sanitized values from the
|
158
173
|
# DatabaseAuthenticatable strategy. If you are using this method on
|
@@ -33,10 +33,14 @@ module Devise
|
|
33
33
|
# Update password saving the record and clearing token. Returns true if
|
34
34
|
# the passwords are valid and the record was saved, false otherwise.
|
35
35
|
def reset_password(new_password, new_password_confirmation)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
if new_password.present?
|
37
|
+
self.password = new_password
|
38
|
+
self.password_confirmation = new_password_confirmation
|
39
|
+
save
|
40
|
+
else
|
41
|
+
errors.add(:password, :blank)
|
42
|
+
false
|
43
|
+
end
|
40
44
|
end
|
41
45
|
|
42
46
|
# Resets reset password token and send reset password instructions by email.
|
@@ -74,7 +74,7 @@ module Devise
|
|
74
74
|
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt.presence)
|
75
75
|
salt
|
76
76
|
else
|
77
|
-
raise "
|
77
|
+
raise "authenticatable_salt returned nil for the #{self.class.name} model. " \
|
78
78
|
"In order to use rememberable, you must ensure a password is always set " \
|
79
79
|
"or have a remember_token column in your model or implement your own " \
|
80
80
|
"rememberable_value in the model with custom logic."
|
data/lib/devise/rails/routes.rb
CHANGED
@@ -338,7 +338,7 @@ module ActionDispatch::Routing
|
|
338
338
|
|
339
339
|
# Sets the devise scope to be used in the controller. If you have custom routes,
|
340
340
|
# you are required to call this method (also aliased as :as) in order to specify
|
341
|
-
# to which controller it is
|
341
|
+
# to which controller it is targeted.
|
342
342
|
#
|
343
343
|
# as :user do
|
344
344
|
# get "sign_in", to: "devise/sessions#new"
|
@@ -65,7 +65,7 @@ module Devise
|
|
65
65
|
scope = resource
|
66
66
|
resource = deprecated
|
67
67
|
|
68
|
-
ActiveSupport::Deprecation.warn <<-DEPRECATION
|
68
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
69
69
|
[Devise] sign_in(:#{scope}, resource) on controller tests is deprecated and will be removed from Devise.
|
70
70
|
Please use sign_in(resource, scope: :#{scope}) instead.
|
71
71
|
DEPRECATION
|
data/lib/devise/test_helpers.rb
CHANGED
@@ -2,7 +2,7 @@ module Devise
|
|
2
2
|
module TestHelpers
|
3
3
|
def self.included(base)
|
4
4
|
base.class_eval do
|
5
|
-
ActiveSupport::Deprecation.warn <<-DEPRECATION
|
5
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
6
6
|
[Devise] including `Devise::TestHelpers` is deprecated and will be removed from Devise.
|
7
7
|
For controller tests, please include `Devise::Test::ControllerHelpers` instead.
|
8
8
|
DEPRECATION
|
data/lib/devise/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class <%= @scope_prefix %>RegistrationsController < Devise::RegistrationsController
|
2
|
-
# before_action :configure_sign_up_params, only: [:create]
|
3
|
-
# before_action :configure_account_update_params, only: [:update]
|
2
|
+
# before_action :configure_sign_up_params, only: [:create]
|
3
|
+
# before_action :configure_account_update_params, only: [:update]
|
4
4
|
|
5
5
|
# GET /resource/sign_up
|
6
6
|
# def new
|
@@ -110,7 +110,10 @@ Devise.setup do |config|
|
|
110
110
|
# Set up a pepper to generate the hashed password.
|
111
111
|
# config.pepper = '<%= SecureRandom.hex(64) %>'
|
112
112
|
|
113
|
-
# Send a notification email when the user's
|
113
|
+
# Send a notification to the original email when the user's email is changed.
|
114
|
+
# config.send_email_changed_notification = false
|
115
|
+
|
116
|
+
# Send a notification email when the user's password is changed.
|
114
117
|
# config.send_password_change_notification = false
|
115
118
|
|
116
119
|
# ==> Configuration for :confirmable
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Hello <%= @email %>!
|
2
|
+
|
3
|
+
<% if @resource.try(:unconfirmed_email?) %>
|
4
|
+
We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.
|
5
|
+
<% else %>
|
6
|
+
We're contacting you to notify you that your email has been changed to <%= @resource.email %>.
|
7
|
+
<% end %>
|
@@ -1,3 +1,3 @@
|
|
1
|
-
|
1
|
+
Hello <%= @resource.email %>!
|
2
2
|
|
3
|
-
|
3
|
+
We're contacting you to notify you that your password has been changed.
|
@@ -164,8 +164,8 @@ class ControllerAuthenticatableTest < Devise::ControllerTestCase
|
|
164
164
|
@controller.instance_variable_set(:@current_user, user)
|
165
165
|
@controller.instance_variable_set(:@current_admin, user)
|
166
166
|
@controller.sign_out
|
167
|
-
|
168
|
-
|
167
|
+
assert_nil @controller.instance_variable_get(:@current_user)
|
168
|
+
assert_nil @controller.instance_variable_get(:@current_admin)
|
169
169
|
end
|
170
170
|
|
171
171
|
test 'sign out logs out and clears up any signed in user by scope' do
|
@@ -175,7 +175,7 @@ class ControllerAuthenticatableTest < Devise::ControllerTestCase
|
|
175
175
|
@mock_warden.expects(:clear_strategies_cache!).with(scope: :user).returns(true)
|
176
176
|
@controller.instance_variable_set(:@current_user, user)
|
177
177
|
@controller.sign_out(:user)
|
178
|
-
|
178
|
+
assert_nil @controller.instance_variable_get(:@current_user)
|
179
179
|
end
|
180
180
|
|
181
181
|
test 'sign out accepts a resource as argument' do
|
@@ -245,7 +245,7 @@ class AuthenticationRoutesRestrictions < Devise::IntegrationTest
|
|
245
245
|
end
|
246
246
|
end
|
247
247
|
|
248
|
-
test 'not signed in users should see
|
248
|
+
test 'not signed in users should see unauthenticated page (unauthenticated accepted)' do
|
249
249
|
get join_path
|
250
250
|
|
251
251
|
assert_response :success
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EmailChangedTest < ActionMailer::TestCase
|
4
|
+
def setup
|
5
|
+
setup_mailer
|
6
|
+
Devise.mailer = 'Devise::Mailer'
|
7
|
+
Devise.mailer_sender = 'test@example.com'
|
8
|
+
Devise.send_email_changed_notification = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
Devise.mailer = 'Devise::Mailer'
|
13
|
+
Devise.mailer_sender = 'please-change-me@config-initializers-devise.com'
|
14
|
+
Devise.send_email_changed_notification = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def user
|
18
|
+
@user ||= create_user.tap { |u|
|
19
|
+
@original_user_email = u.email
|
20
|
+
u.update_attributes!(email: 'new-email@example.com')
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def mail
|
25
|
+
@mail ||= begin
|
26
|
+
user
|
27
|
+
ActionMailer::Base.deliveries.last
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
test 'email sent after changing the user email' do
|
32
|
+
assert_not_nil mail
|
33
|
+
end
|
34
|
+
|
35
|
+
test 'content type should be set to html' do
|
36
|
+
assert mail.content_type.include?('text/html')
|
37
|
+
end
|
38
|
+
|
39
|
+
test 'send email changed to the original user email' do
|
40
|
+
mail
|
41
|
+
assert_equal [@original_user_email], mail.to
|
42
|
+
end
|
43
|
+
|
44
|
+
test 'set up sender from configuration' do
|
45
|
+
assert_equal ['test@example.com'], mail.from
|
46
|
+
end
|
47
|
+
|
48
|
+
test 'set up sender from custom mailer defaults' do
|
49
|
+
Devise.mailer = 'Users::Mailer'
|
50
|
+
assert_equal ['custom@example.com'], mail.from
|
51
|
+
end
|
52
|
+
|
53
|
+
test 'set up sender from custom mailer defaults with proc' do
|
54
|
+
Devise.mailer = 'Users::FromProcMailer'
|
55
|
+
assert_equal ['custom@example.com'], mail.from
|
56
|
+
end
|
57
|
+
|
58
|
+
test 'custom mailer renders parent mailer template' do
|
59
|
+
Devise.mailer = 'Users::Mailer'
|
60
|
+
assert_present mail.body.encoded
|
61
|
+
end
|
62
|
+
|
63
|
+
test 'set up reply to as copy from sender' do
|
64
|
+
assert_equal ['test@example.com'], mail.reply_to
|
65
|
+
end
|
66
|
+
|
67
|
+
test 'set up reply to as different if set in defaults' do
|
68
|
+
Devise.mailer = 'Users::ReplyToMailer'
|
69
|
+
assert_equal ['custom@example.com'], mail.from
|
70
|
+
assert_equal ['custom_reply_to@example.com'], mail.reply_to
|
71
|
+
end
|
72
|
+
|
73
|
+
test 'set up subject from I18n' do
|
74
|
+
store_translations :en, devise: { mailer: { email_changed: { subject: 'Email Has Changed' } } } do
|
75
|
+
assert_equal 'Email Has Changed', mail.subject
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
test 'subject namespaced by model' do
|
80
|
+
store_translations :en, devise: { mailer: { email_changed: { user_subject: 'User Email Has Changed' } } } do
|
81
|
+
assert_equal 'User Email Has Changed', mail.subject
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
test 'body should have user info' do
|
86
|
+
body = mail.body.encoded
|
87
|
+
assert_match "Hello #{@original_user_email}", body
|
88
|
+
assert_match "has been changed to #{user.email}", body
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class EmailChangedReconfirmationTest < ActionMailer::TestCase
|
93
|
+
def setup
|
94
|
+
setup_mailer
|
95
|
+
Devise.mailer = 'Devise::Mailer'
|
96
|
+
Devise.mailer_sender = 'test@example.com'
|
97
|
+
Devise.send_email_changed_notification = true
|
98
|
+
end
|
99
|
+
|
100
|
+
def teardown
|
101
|
+
Devise.mailer = 'Devise::Mailer'
|
102
|
+
Devise.mailer_sender = 'please-change-me@config-initializers-devise.com'
|
103
|
+
Devise.send_email_changed_notification = false
|
104
|
+
end
|
105
|
+
|
106
|
+
def admin
|
107
|
+
@admin ||= create_admin.tap { |u|
|
108
|
+
@original_admin_email = u.email
|
109
|
+
u.update_attributes!(email: 'new-email@example.com')
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def mail
|
114
|
+
@mail ||= begin
|
115
|
+
admin
|
116
|
+
ActionMailer::Base.deliveries[-2]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
test 'send email changed to the original user email' do
|
121
|
+
mail
|
122
|
+
assert_equal [@original_admin_email], mail.to
|
123
|
+
end
|
124
|
+
|
125
|
+
test 'body should have unconfirmed user info' do
|
126
|
+
body = mail.body.encoded
|
127
|
+
assert_match admin.email, body
|
128
|
+
assert_match "is being changed to #{admin.unconfirmed_email}", body
|
129
|
+
end
|
130
|
+
end
|