accounts 0.0.1
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/.gitignore +2 -0
- data/.rvmrc +53 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +167 -0
- data/README.mkd +105 -0
- data/Rakefile +24 -0
- data/accounts.gemspec +52 -0
- data/demo/views/change_email.haml +14 -0
- data/demo/views/change_password.haml +36 -0
- data/demo/views/forgot_password.haml +21 -0
- data/demo/views/logon.haml +24 -0
- data/demo/views/register.haml +15 -0
- data/demo/web_app.rb +99 -0
- data/features/change-email.feature +51 -0
- data/features/change-password.feature +89 -0
- data/features/register.feature +42 -0
- data/features/step_definitions/steps.rb +102 -0
- data/features/step_definitions/web_steps.rb +228 -0
- data/features/support/env.rb +18 -0
- data/features/support/paths.rb +29 -0
- data/features/support/unused.rb +29 -0
- data/lib/accounts.rb +79 -0
- data/lib/accounts/configure.rb +122 -0
- data/lib/accounts/helpers.rb +90 -0
- data/lib/accounts/model.rb +126 -0
- data/lib/accounts/version.rb +5 -0
- data/spec/user_model_spec.rb +105 -0
- metadata +263 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
# Taken from the cucumber-rails project.
|
2
|
+
# IMPORTANT: This file is generated by cucumber-sinatra - edit at your own peril.
|
3
|
+
# It is recommended to regenerate this file in the future when you upgrade to a
|
4
|
+
# newer version of cucumber-sinatra. Consider adding your own code to a new file
|
5
|
+
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
6
|
+
# files.
|
7
|
+
|
8
|
+
require 'uri'
|
9
|
+
require 'cgi'
|
10
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
|
11
|
+
|
12
|
+
module WithinHelpers
|
13
|
+
def with_scope(locator)
|
14
|
+
locator ? within(locator) { yield } : yield
|
15
|
+
end
|
16
|
+
end
|
17
|
+
World(WithinHelpers)
|
18
|
+
|
19
|
+
Given /^(?:\w+ )am on (.+)$/ do |page_name|
|
20
|
+
visit path_to(page_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
When /^(?:\w+ )go to (.+)$/ do |page_name|
|
24
|
+
visit path_to(page_name)
|
25
|
+
end
|
26
|
+
|
27
|
+
When /^(?:\w+ )press(?:es)? "([^\"]*)"(?: within "([^\"]*)")?$/ do |button, selector|
|
28
|
+
with_scope(selector) do
|
29
|
+
click_button(button)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
When /^(?:\w+ )follows? "([^\"]*)"(?: within "([^\"]*)")?$/ do |link, selector|
|
34
|
+
with_scope(selector) do
|
35
|
+
click_link(link)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
When /^(?:\w+ )fills? in "([^\"]*)" with "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, value, selector|
|
40
|
+
with_scope(selector) do
|
41
|
+
fill_in(field, :with => value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
When /^(?:\w+ )fills? in "([^\"]*)" for "([^\"]*)"(?: within "([^\"]*)")?$/ do |value, field, selector|
|
46
|
+
with_scope(selector) do
|
47
|
+
fill_in(field, :with => value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Use this to fill in an entire form with data from a table. Example:
|
52
|
+
#
|
53
|
+
# When I fill in the following:
|
54
|
+
# | Account Number | 5002 |
|
55
|
+
# | Expiry date | 2009-11-01 |
|
56
|
+
# | Note | Nice guy |
|
57
|
+
# | Wants Email? | |
|
58
|
+
#
|
59
|
+
# TODO: Add support for checkbox, select og option
|
60
|
+
# based on naming conventions.
|
61
|
+
#
|
62
|
+
When /^(?:\w+ )fills? in the following(?: within "([^\"]*)")?:$/ do |selector, fields|
|
63
|
+
with_scope(selector) do
|
64
|
+
fields.rows_hash.each do |name, value|
|
65
|
+
When %{I fill in "#{name}" with "#{value}"}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
When /^(?:\w+ )select "([^\"]*)" from "([^\"]*)"(?: within "([^\"]*)")?$/ do |value, field, selector|
|
71
|
+
with_scope(selector) do
|
72
|
+
select(value, :from => field)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
When /^(?:\w+ )check "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, selector|
|
77
|
+
with_scope(selector) do
|
78
|
+
check(field)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
When /^(?:\w+ )uncheck "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, selector|
|
83
|
+
with_scope(selector) do
|
84
|
+
uncheck(field)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
When /^(?:\w+ )choose "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, selector|
|
89
|
+
with_scope(selector) do
|
90
|
+
choose(field)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
When /^(?:\w+ )attach the file "([^\"]*)" to "([^\"]*)"(?: within "([^\"]*)")?$/ do |path, field, selector|
|
95
|
+
with_scope(selector) do
|
96
|
+
attach_file(field, path)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Then /^(?:\w+ )should see JSON:$/ do |expected_json|
|
101
|
+
require 'json'
|
102
|
+
expected = JSON.pretty_generate(JSON.parse(expected_json))
|
103
|
+
actual = JSON.pretty_generate(JSON.parse(response.body))
|
104
|
+
expected.should == actual
|
105
|
+
end
|
106
|
+
|
107
|
+
Then /^(?:\w+ )should see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, selector|
|
108
|
+
with_scope(selector) do
|
109
|
+
if page.respond_to? :should
|
110
|
+
page.should have_content(text)
|
111
|
+
else
|
112
|
+
assert page.has_content?(text)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
Then /^(?:\w+ )should see \/([^\/]*)\/(?: within "([^\"]*)")?$/ do |regexp, selector|
|
118
|
+
regexp = Regexp.new(regexp)
|
119
|
+
with_scope(selector) do
|
120
|
+
if page.respond_to? :should
|
121
|
+
page.should have_xpath('//*', :text => regexp)
|
122
|
+
else
|
123
|
+
assert page.has_xpath?('//*', :text => regexp)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
Then /^(?:\w+ )should not see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, selector|
|
129
|
+
with_scope(selector) do
|
130
|
+
if page.respond_to? :should
|
131
|
+
page.should have_no_content(text)
|
132
|
+
else
|
133
|
+
assert page.has_no_content?(text)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
Then /^(?:\w+ )should not see \/([^\/]*)\/(?: within "([^\"]*)")?$/ do |regexp, selector|
|
139
|
+
regexp = Regexp.new(regexp)
|
140
|
+
with_scope(selector) do
|
141
|
+
if page.respond_to? :should
|
142
|
+
page.should have_no_xpath('//*', :text => regexp)
|
143
|
+
else
|
144
|
+
assert page.has_no_xpath?('//*', :text => regexp)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Then /^the "([^\"]*)" field(?: within "([^\"]*)")? should contain "([^\"]*)"$/ do |field, selector, value|
|
150
|
+
with_scope(selector) do
|
151
|
+
field = find_field(field)
|
152
|
+
field_value = (field.tag_name == 'textarea') ? field.text : field.value
|
153
|
+
if field_value.respond_to? :should
|
154
|
+
field_value.should =~ /#{value}/
|
155
|
+
else
|
156
|
+
assert_match(/#{value}/, field_value)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
Then /^the "([^\"]*)" field(?: within "([^\"]*)")? should not contain "([^\"]*)"$/ do |field, selector, value|
|
162
|
+
with_scope(selector) do
|
163
|
+
field = find_field(field)
|
164
|
+
field_value = (field.tag_name == 'textarea') ? field.text : field.value
|
165
|
+
if field_value.respond_to? :should_not
|
166
|
+
field_value.should_not =~ /#{value}/
|
167
|
+
else
|
168
|
+
assert_no_match(/#{value}/, field_value)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Then /^the "([^\"]*)" checkbox(?: within "([^\"]*)")? should be checked$/ do |label, selector|
|
174
|
+
with_scope(selector) do
|
175
|
+
field_checked = find_field(label)['checked']
|
176
|
+
if field_checked.respond_to? :should
|
177
|
+
field_checked.should == 'checked'
|
178
|
+
else
|
179
|
+
assert_equal 'checked', field_checked
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
Then /^the "([^\"]*)" checkbox(?: within "([^\"]*)")? should not be checked$/ do |label, selector|
|
185
|
+
with_scope(selector) do
|
186
|
+
field_checked = find_field(label)['checked']
|
187
|
+
if field_checked.respond_to? :should_not
|
188
|
+
field_checked.should_not == 'checked'
|
189
|
+
else
|
190
|
+
assert_not_equal 'checked', field_checked
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
Then /^(?:\w+ )should be on "([^\"]*)"$/ do |pat|
|
196
|
+
current_path = URI.parse(current_url).path
|
197
|
+
if current_path.respond_to? :should
|
198
|
+
current_path.should match pat
|
199
|
+
else
|
200
|
+
assert_true current_path.match(pat)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
Then /^(?:\w+ )should be on (.+)$ page$/ do |page_name|
|
205
|
+
current_path = URI.parse(current_url).path
|
206
|
+
if current_path.respond_to? :should
|
207
|
+
current_path.should == path_to(page_name)
|
208
|
+
else
|
209
|
+
assert_equal path_to(page_name), current_path
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
Then /^(?:\w+ )should have the following query string:$/ do |expected_pairs|
|
214
|
+
query = URI.parse(current_url).query
|
215
|
+
actual_params = query ? CGI.parse(query) : {}
|
216
|
+
expected_params = {}
|
217
|
+
expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
|
218
|
+
|
219
|
+
if actual_params.respond_to? :should
|
220
|
+
actual_params.should == expected_params
|
221
|
+
else
|
222
|
+
assert_equal expected_params, actual_params
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
Then /^show me the page$/ do
|
227
|
+
save_and_open_page
|
228
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright Westside Consulting LLC, Ann Arbor, MI, USA, 2012
|
2
|
+
|
3
|
+
require './demo/web_app'
|
4
|
+
require 'capybara/cucumber'
|
5
|
+
|
6
|
+
Capybara.app = MyWebApp
|
7
|
+
|
8
|
+
class AccountsWorld
|
9
|
+
include Capybara::DSL
|
10
|
+
include RSpec::Expectations
|
11
|
+
include RSpec::Matchers
|
12
|
+
end
|
13
|
+
|
14
|
+
World do |;world|
|
15
|
+
world = AccountsWorld.new
|
16
|
+
#STDERR.puts world.class.included_modules
|
17
|
+
#File.open("/tmp/methods.txt", "w").puts world.methods
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Taken from the cucumber-rails project.
|
2
|
+
|
3
|
+
module NavigationHelpers
|
4
|
+
# Maps a name to a path. Used by the
|
5
|
+
#
|
6
|
+
# When /^I go to (.+)$/ do |page_name|
|
7
|
+
#
|
8
|
+
# step definition in web_steps.rb
|
9
|
+
#
|
10
|
+
def path_to(page_name)
|
11
|
+
case page_name
|
12
|
+
|
13
|
+
when /the home\s?page/
|
14
|
+
'/'
|
15
|
+
|
16
|
+
# Add more mappings here.
|
17
|
+
# Here is an example that pulls values out of the Regexp:
|
18
|
+
#
|
19
|
+
# when /^(.*)'s profile page$/i
|
20
|
+
# user_profile_path(User.find_by_login($1))
|
21
|
+
|
22
|
+
else
|
23
|
+
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
24
|
+
"Now, go and add a mapping in #{__FILE__}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
World(NavigationHelpers)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# From http://www.natontesting.com/2011/04/05/cucumber-formatter-for-unused-steps/
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
|
4
|
+
#
|
5
|
+
# http://www.natontesting.com
|
6
|
+
#
|
7
|
+
# Save this in a file called 'unused.rb' in your 'features/support' directory. Then, to list
|
8
|
+
# all the unused steps in your project, run the following command:
|
9
|
+
#
|
10
|
+
# cucumber -d -f Cucumber::Formatter::Unused
|
11
|
+
#
|
12
|
+
# or...
|
13
|
+
#
|
14
|
+
# cucumber -d -f Unused
|
15
|
+
|
16
|
+
require 'cucumber/formatter/stepdefs'
|
17
|
+
|
18
|
+
class Unused < Cucumber::Formatter::Stepdefs
|
19
|
+
def print_summary(features)
|
20
|
+
add_unused_stepdefs
|
21
|
+
keys = @stepdef_to_match.keys.sort {|a,b| a.regexp_source <=> b.regexp_source}
|
22
|
+
puts "The following steps are unused...\n---------"
|
23
|
+
keys.each do |stepdef_key|
|
24
|
+
if @stepdef_to_match[stepdef_key].none?
|
25
|
+
puts "#{stepdef_key.regexp_source}\n#{stepdef_key.file_colon_line}\n---"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/accounts.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright Westside Consulting LLC, Ann Arbor, MI, USA, 2012
|
2
|
+
|
3
|
+
require 'accounts/version'
|
4
|
+
require 'accounts/model'
|
5
|
+
require 'accounts/configure'
|
6
|
+
require 'accounts/helpers'
|
7
|
+
|
8
|
+
module Accounts
|
9
|
+
|
10
|
+
class Server < ::Sinatra::Base
|
11
|
+
|
12
|
+
helpers do
|
13
|
+
include ::Accounts::Helpers
|
14
|
+
end
|
15
|
+
|
16
|
+
error ::Accounts::AccountsError do
|
17
|
+
env['sinatra.error'].return_error_page
|
18
|
+
end
|
19
|
+
|
20
|
+
post '/logon' do
|
21
|
+
email = params[:email]
|
22
|
+
password = params[:password]
|
23
|
+
|
24
|
+
if authenticate! email, password then
|
25
|
+
redirect to Accounts.redirect_after_logon
|
26
|
+
else
|
27
|
+
session[:account_id] = nil
|
28
|
+
halt 403
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
post '/register' do
|
33
|
+
email = params[:email]
|
34
|
+
account = ::Accounts::Account.first({ :email => email })
|
35
|
+
case
|
36
|
+
when !account
|
37
|
+
register_new_account email
|
38
|
+
halt Accounts.post_register_new_account_response
|
39
|
+
when account.status.include?(:email_confirmed)
|
40
|
+
halt Accounts.post_register_already_registered_response[email]
|
41
|
+
end
|
42
|
+
send_change_password_link account
|
43
|
+
Accounts.post_register_new_account_response
|
44
|
+
end
|
45
|
+
|
46
|
+
post '/forgot-password' do
|
47
|
+
email = params[:email]
|
48
|
+
account = ::Accounts::Account.first({ :email => email }) \
|
49
|
+
or halt Accounts.post_forgot_password_email_does_not_match_response[email]
|
50
|
+
send_change_password_link account
|
51
|
+
Accounts.post_forgot_password_response
|
52
|
+
end
|
53
|
+
|
54
|
+
post '/change-password' do
|
55
|
+
halt 403 unless session[:account_id]
|
56
|
+
account = ::Accounts::Account.get(session[:account_id]) \
|
57
|
+
or halt 403
|
58
|
+
account.set_password params[:password]
|
59
|
+
Accounts.deliver_change_password_confirmation[account.email]
|
60
|
+
Accounts.changed_your_password_response
|
61
|
+
end
|
62
|
+
|
63
|
+
post '/change-email' do
|
64
|
+
halt 403 unless session[:account_id]
|
65
|
+
account = ::Accounts::Account.get(session[:account_id]) \
|
66
|
+
or halt 403
|
67
|
+
new_email = params[:email]
|
68
|
+
::Accounts::Account.count(:email => new_email) == 0 \
|
69
|
+
or halt "#{new_email} is already taken"
|
70
|
+
send_change_email_confirmation account, new_email
|
71
|
+
Accounts.deliver_change_email_notification[account.email, new_email]
|
72
|
+
Accounts.post_change_email_response
|
73
|
+
end
|
74
|
+
|
75
|
+
get '/response-token/:token' do
|
76
|
+
respond_to_token params[:token]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Copyright Westside Consulting LLC, Ann Arbor, MI, USA, 2012
|
2
|
+
|
3
|
+
module Accounts
|
4
|
+
class << self
|
5
|
+
attr_accessor :page_not_found # String
|
6
|
+
attr_accessor :redirect_after_logon # String
|
7
|
+
attr_accessor :post_forgot_password_response # String
|
8
|
+
attr_accessor :changed_your_password_response # String
|
9
|
+
attr_accessor :post_register_new_account_response # String
|
10
|
+
attr_accessor :post_register_already_registered_response # Proc(email)
|
11
|
+
attr_accessor :post_forgot_password_email_does_not_match_response # Proc(email)
|
12
|
+
attr_accessor :post_change_email_response # String
|
13
|
+
attr_accessor :admin_email # String
|
14
|
+
attr_accessor :deliver_registration_confirmation # Proc(email, link)
|
15
|
+
attr_accessor :deliver_change_password_link # Proc(email, link)
|
16
|
+
attr_accessor :deliver_change_password_confirmation # Proc(email)
|
17
|
+
attr_accessor :deliver_change_email_confirmation # Proc(old_email, new_email, link)
|
18
|
+
attr_accessor :deliver_new_account_admin_notification #Proc(email)
|
19
|
+
attr_accessor :deliver_change_email_notification #Proc(old_email, new_email)
|
20
|
+
|
21
|
+
##
|
22
|
+
# Configure Accounts with your custom pages and e-mails.
|
23
|
+
#
|
24
|
+
# Accounts.configure do |config|
|
25
|
+
# config.changed_your_password_response = "You have changed your password."
|
26
|
+
# config.redirect_after_logon = "/welcome"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# See lib/accounts/configure.rb for complete example.
|
30
|
+
#
|
31
|
+
# All config params that are strings may be replaced with Procs.
|
32
|
+
def configure
|
33
|
+
yield self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set defaults - can be overiden
|
39
|
+
Accounts.configure do |config|
|
40
|
+
|
41
|
+
config.changed_your_password_response = "You have changed your password."
|
42
|
+
config.redirect_after_logon = "/welcome"
|
43
|
+
config.post_register_new_account_response = "Check your e-mail."
|
44
|
+
config.post_forgot_password_response = "Check your e-mail to change your password."
|
45
|
+
config.post_change_email_response = "Check your e-mail."
|
46
|
+
config.admin_email = 'admin@accounts.test'
|
47
|
+
|
48
|
+
config.post_forgot_password_email_does_not_match_response = ->(email) {
|
49
|
+
%Q{#{email} does not match any account. You may <a href="/register">register here</a>.}
|
50
|
+
}
|
51
|
+
|
52
|
+
config.post_register_already_registered_response = ->(email) {
|
53
|
+
%Q{#{email} is already registered. You may <a href="/logon?email=#{email}"log on</a>.}
|
54
|
+
}
|
55
|
+
|
56
|
+
config.deliver_registration_confirmation = ->(email, link) {
|
57
|
+
Mail.deliver do
|
58
|
+
from Accounts.admin_email
|
59
|
+
to email
|
60
|
+
subject 'Your e-mail is confirmed'
|
61
|
+
body %Q{You have registered for accounts.test.
|
62
|
+
|
63
|
+
Follow this link to confirm your e-mail address and set your password: #{link}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
}
|
67
|
+
|
68
|
+
config.deliver_change_password_link = ->(email, link) {
|
69
|
+
Mail.deliver do
|
70
|
+
from Accounts.admin_email
|
71
|
+
to email
|
72
|
+
subject 'How to change your password'
|
73
|
+
body "Follow this link to change your password: #{link}"
|
74
|
+
end
|
75
|
+
}
|
76
|
+
|
77
|
+
config.deliver_change_password_confirmation = ->(email) {
|
78
|
+
Mail.deliver do
|
79
|
+
from Accounts.admin_email
|
80
|
+
to email
|
81
|
+
subject 'Your password has changed'
|
82
|
+
body "The password for #{email} has changed."
|
83
|
+
end
|
84
|
+
}
|
85
|
+
|
86
|
+
config.deliver_change_email_confirmation = ->(old_email, new_email, link) {
|
87
|
+
Mail.deliver do
|
88
|
+
from Accounts.admin_email
|
89
|
+
to new_email
|
90
|
+
subject 'You requested to change your e-mail'
|
91
|
+
body %Q{You have requested to change your e-mail to #{new_email}."
|
92
|
+
|
93
|
+
You must visit this link to confirm: #{link}
|
94
|
+
|
95
|
+
#{old_email} has also been sent a notification e-mail.
|
96
|
+
}
|
97
|
+
end
|
98
|
+
}
|
99
|
+
config.deliver_new_account_admin_notification = ->(email) {
|
100
|
+
Mail.deliver do
|
101
|
+
from Accounts.admin_email
|
102
|
+
to Accounts.admin_email
|
103
|
+
subject 'new account has confirmed e-mail'
|
104
|
+
body "#{email} has registered and confirmed"
|
105
|
+
end
|
106
|
+
}
|
107
|
+
|
108
|
+
config.deliver_change_email_notification = ->(old_email, new_email) {
|
109
|
+
Mail.deliver do
|
110
|
+
from Accounts.admin_email
|
111
|
+
to old_email
|
112
|
+
subject 'You requested to change your e-mail'
|
113
|
+
body %Q{You have requested to change your e-mail to #{new_email}."
|
114
|
+
|
115
|
+
An e-mail has been sent to #{new_email}.
|
116
|
+
|
117
|
+
Please open that mail and follow the instructions.
|
118
|
+
}
|
119
|
+
end
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|