thoughtbot-clearance 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb +2 -5
- data/generators/clearance/templates/app/views/clearance_mailer/confirmation.html.erb +2 -1
- data/generators/clearance/templates/app/views/passwords/edit.html.erb +2 -4
- data/generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb +8 -9
- data/generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb +7 -8
- data/lib/clearance/app/controllers/application_controller.rb +2 -2
- data/lib/clearance/app/controllers/confirmations_controller.rb +2 -2
- data/lib/clearance/app/controllers/passwords_controller.rb +4 -8
- data/lib/clearance/app/controllers/sessions_controller.rb +2 -2
- data/lib/clearance/app/models/user.rb +39 -11
- data/lib/clearance/test/functional/confirmations_controller_test.rb +7 -7
- data/lib/clearance/test/functional/passwords_controller_test.rb +106 -102
- data/lib/clearance/test/functional/sessions_controller_test.rb +15 -24
- data/lib/clearance/test/functional/users_controller_test.rb +1 -13
- data/lib/clearance/test/unit/clearance_mailer_test.rb +2 -2
- data/lib/clearance/test/unit/user_test.rb +73 -11
- data/shoulda_macros/clearance.rb +72 -0
- metadata +42 -42
data/Rakefile
CHANGED
@@ -35,7 +35,7 @@ task :default => 'test:all'
|
|
35
35
|
|
36
36
|
gem_spec = Gem::Specification.new do |gem_spec|
|
37
37
|
gem_spec.name = "clearance"
|
38
|
-
gem_spec.version = "0.4.
|
38
|
+
gem_spec.version = "0.4.2"
|
39
39
|
gem_spec.summary = "Rails authentication for developers who write tests."
|
40
40
|
gem_spec.email = "support@thoughtbot.com"
|
41
41
|
gem_spec.homepage = "http://github.com/thoughtbot/clearance"
|
@@ -2,9 +2,6 @@ Someone, hopefully you, has requested that we send you a link to change your pas
|
|
2
2
|
|
3
3
|
Here's the link:
|
4
4
|
|
5
|
-
<%= edit_user_password_url(@user,
|
6
|
-
:email => @user.email,
|
7
|
-
:password => @user.encrypted_password,
|
8
|
-
:escape => false) %>
|
5
|
+
<%= edit_user_password_url(@user, :token => @user.token, :escape => false) %>
|
9
6
|
|
10
|
-
If you didn't request this,
|
7
|
+
If you didn't request this, ignore this email. Don't worry. Your password hasn't been changed.
|
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
<%= new_user_confirmation_url :user_id => @user, :token => @user.token, :encode => false %>
|
@@ -7,9 +7,7 @@
|
|
7
7
|
<%= error_messages_for :user %>
|
8
8
|
|
9
9
|
<% form_for(:user,
|
10
|
-
:url => user_password_path(@user,
|
11
|
-
:email => @user.email,
|
12
|
-
:password => @user.encrypted_password),
|
10
|
+
:url => user_password_path(@user, :token => @user.token),
|
13
11
|
:html => { :method => :put }) do |form| %>
|
14
12
|
<div class="password_field">
|
15
13
|
<%= form.label :password, "Choose password" %>
|
@@ -22,4 +20,4 @@
|
|
22
20
|
<div class="submit_field">
|
23
21
|
<%= form.submit "Save this password", :disable_with => "Please wait..." %>
|
24
22
|
</div>
|
25
|
-
<% end %>
|
23
|
+
<% end %>
|
@@ -1,18 +1,17 @@
|
|
1
1
|
class CreateOrUpdateUsersWithClearanceColumns < ActiveRecord::Migration
|
2
2
|
def self.up
|
3
3
|
create_table(:users) do |t|
|
4
|
-
t.string
|
5
|
-
t.string
|
6
|
-
t.string
|
7
|
-
t.string
|
8
|
-
t.datetime :
|
9
|
-
t.boolean
|
4
|
+
t.string :email
|
5
|
+
t.string :encrypted_password, :limit => 128
|
6
|
+
t.string :salt, :limit => 128
|
7
|
+
t.string :token, :limit => 128
|
8
|
+
t.datetime :token_expires_at
|
9
|
+
t.boolean :email_confirmed, :default => false, :null => false
|
10
10
|
end
|
11
11
|
|
12
|
-
add_index :users, [:
|
13
|
-
add_index :users, [:id, :salt]
|
12
|
+
add_index :users, [:id, :token]
|
14
13
|
add_index :users, :email
|
15
|
-
add_index :users, :
|
14
|
+
add_index :users, :token
|
16
15
|
end
|
17
16
|
|
18
17
|
def self.down
|
@@ -4,10 +4,10 @@ class CreateOrUpdateUsersWithClearanceColumns < ActiveRecord::Migration
|
|
4
4
|
existing_columns = ActiveRecord::Base.connection.columns(:users).collect { |each| each.name }
|
5
5
|
columns = [
|
6
6
|
[:email, 't.string :email'],
|
7
|
-
[:encrypted_password, 't.string :encrypted_password, :limit =>
|
8
|
-
[:salt, 't.string :salt, :limit =>
|
9
|
-
[:
|
10
|
-
[:
|
7
|
+
[:encrypted_password, 't.string :encrypted_password, :limit => 128'],
|
8
|
+
[:salt, 't.string :salt, :limit => 128'],
|
9
|
+
[:token, 't.string :token, :limit => 128'],
|
10
|
+
[:token_expires_at, 't.datetime :token_expires_at'],
|
11
11
|
[:email_confirmed, 't.boolean :email_confirmed, :default => false, :null => false']
|
12
12
|
].delete_if {|c| existing_columns.include?(c.first.to_s)}
|
13
13
|
-%>
|
@@ -21,10 +21,9 @@ class CreateOrUpdateUsersWithClearanceColumns < ActiveRecord::Migration
|
|
21
21
|
existing_indexes = ActiveRecord::Base.connection.indexes(:users)
|
22
22
|
index_names = existing_indexes.collect { |each| each.name }
|
23
23
|
new_indexes = [
|
24
|
-
[:
|
25
|
-
[:
|
26
|
-
[:
|
27
|
-
[:index_users_on_remember_token, 'add_index :users, :remember_token']
|
24
|
+
[:index_users_on_id_and_token, 'add_index :users, [:id, :token]'],
|
25
|
+
[:index_users_on_email, 'add_index :users, :email'],
|
26
|
+
[:index_users_on_token, 'add_index :users, :token']
|
28
27
|
].delete_if { |each| index_names.include?(each.first.to_s) }
|
29
28
|
-%>
|
30
29
|
<% new_indexes.each do |each| -%>
|
@@ -28,15 +28,15 @@ module Clearance
|
|
28
28
|
def user_from_session
|
29
29
|
if session[:user_id] && session[:salt]
|
30
30
|
user = User.find_by_id_and_salt(session[:user_id], session[:salt])
|
31
|
+
user && user.email_confirmed? ? user : nil
|
31
32
|
end
|
32
|
-
user && user.email_confirmed? ? user : nil
|
33
33
|
end
|
34
34
|
|
35
35
|
def user_from_cookie
|
36
36
|
if cookies[:remember_token]
|
37
37
|
user = User.find_by_remember_token(cookies[:remember_token])
|
38
|
+
user && user.remember? ? user : nil
|
38
39
|
end
|
39
|
-
user && user.remember? ? user : nil
|
40
40
|
end
|
41
41
|
|
42
42
|
# Hook
|
@@ -7,7 +7,7 @@ module Clearance
|
|
7
7
|
controller.class_eval do
|
8
8
|
|
9
9
|
before_filter :existing_user?, :only => :new
|
10
|
-
filter_parameter_logging :
|
10
|
+
filter_parameter_logging :token
|
11
11
|
|
12
12
|
def new
|
13
13
|
create
|
@@ -23,7 +23,7 @@ module Clearance
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def existing_user?
|
26
|
-
@user = User.
|
26
|
+
@user = User.find_by_id_and_token(params[:user_id], params[:token])
|
27
27
|
if @user.nil?
|
28
28
|
render :nothing => true, :status => :not_found
|
29
29
|
end
|
@@ -18,6 +18,7 @@ module Clearance
|
|
18
18
|
flash.now[:notice] = "Unknown email"
|
19
19
|
render :action => :new
|
20
20
|
else
|
21
|
+
user.forgot_password!
|
21
22
|
ClearanceMailer.deliver_change_password user
|
22
23
|
flash[:notice] = "Details for changing your password " <<
|
23
24
|
"have been sent to #{user.email}"
|
@@ -26,14 +27,10 @@ module Clearance
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def edit
|
29
|
-
@user = User.find_by_email_and_encrypted_password(params[:email],
|
30
|
-
params[:password])
|
31
30
|
end
|
32
31
|
|
33
32
|
def update
|
34
|
-
@user
|
35
|
-
params[:password])
|
36
|
-
if @user.update_attributes params[:user]
|
33
|
+
if @user.update_password(params[:user])
|
37
34
|
sign_user_in(@user)
|
38
35
|
redirect_to url_after_update
|
39
36
|
else
|
@@ -44,9 +41,8 @@ module Clearance
|
|
44
41
|
private
|
45
42
|
|
46
43
|
def existing_user?
|
47
|
-
user = User.
|
48
|
-
|
49
|
-
if user.nil?
|
44
|
+
@user = User.find_by_id_and_token(params[:user_id], params[:token])
|
45
|
+
if @user.nil?
|
50
46
|
render :nothing => true, :status => :not_found
|
51
47
|
end
|
52
48
|
end
|
@@ -42,8 +42,8 @@ module Clearance
|
|
42
42
|
|
43
43
|
def remember(user)
|
44
44
|
user.remember_me!
|
45
|
-
cookies[:remember_token] = { :value => user.
|
46
|
-
:expires => user.
|
45
|
+
cookies[:remember_token] = { :value => user.token,
|
46
|
+
:expires => user.token_expires_at }
|
47
47
|
end
|
48
48
|
|
49
49
|
def forget(user)
|
@@ -17,7 +17,7 @@ module Clearance
|
|
17
17
|
validates_uniqueness_of :email, :case_sensitive => false
|
18
18
|
validates_format_of :email, :with => %r{.+@.+\..+}
|
19
19
|
|
20
|
-
before_save :initialize_salt, :encrypt_password, :downcase_email
|
20
|
+
before_save :initialize_salt, :encrypt_password, :initialize_token, :downcase_email
|
21
21
|
|
22
22
|
def self.authenticate(email, password)
|
23
23
|
user = find(:first, :conditions => ['LOWER(email) = ?', email.to_s.downcase])
|
@@ -29,11 +29,11 @@ module Clearance
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def encrypt(string)
|
32
|
-
|
32
|
+
generate_hash("--#{salt}--#{string}--")
|
33
33
|
end
|
34
34
|
|
35
35
|
def remember?
|
36
|
-
|
36
|
+
token_expires_at && Time.now.utc < token_expires_at
|
37
37
|
end
|
38
38
|
|
39
39
|
def remember_me!
|
@@ -41,29 +41,43 @@ module Clearance
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def remember_me_until(time)
|
44
|
-
self.
|
45
|
-
self.
|
46
|
-
|
44
|
+
self.token_expires_at = time
|
45
|
+
self.token = encrypt("--#{token_expires_at}--#{password}--")
|
46
|
+
save(false)
|
47
47
|
end
|
48
48
|
|
49
49
|
def forget_me!
|
50
|
-
|
51
|
-
|
50
|
+
clear_token
|
51
|
+
save(false)
|
52
52
|
end
|
53
53
|
|
54
54
|
def confirm_email!
|
55
|
-
self.
|
55
|
+
self.email_confirmed = true
|
56
|
+
self.token = nil
|
57
|
+
save(false)
|
58
|
+
end
|
59
|
+
|
60
|
+
def forgot_password!
|
61
|
+
generate_token
|
62
|
+
save(false)
|
63
|
+
end
|
64
|
+
|
65
|
+
def update_password(attrs)
|
66
|
+
clear_token
|
67
|
+
returning update_attributes(attrs) do |r|
|
68
|
+
reload unless r
|
69
|
+
end
|
56
70
|
end
|
57
71
|
|
58
72
|
protected
|
59
73
|
|
60
|
-
def
|
74
|
+
def generate_hash(string)
|
61
75
|
Digest::SHA512.hexdigest(string)
|
62
76
|
end
|
63
77
|
|
64
78
|
def initialize_salt
|
65
79
|
if new_record?
|
66
|
-
self.salt =
|
80
|
+
self.salt = generate_hash("--#{Time.now.utc.to_s}--#{password}--")
|
67
81
|
end
|
68
82
|
end
|
69
83
|
|
@@ -71,6 +85,20 @@ module Clearance
|
|
71
85
|
return if password.blank?
|
72
86
|
self.encrypted_password = encrypt(password)
|
73
87
|
end
|
88
|
+
|
89
|
+
def generate_token
|
90
|
+
self.token = encrypt("--#{Time.now.utc.to_s}--#{password}--")
|
91
|
+
self.token_expires_at = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def clear_token
|
95
|
+
self.token = nil
|
96
|
+
self.token_expires_at = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize_token
|
100
|
+
generate_token if new_record?
|
101
|
+
end
|
74
102
|
|
75
103
|
def password_required?
|
76
104
|
encrypted_password.blank? || !password.blank?
|
@@ -6,14 +6,14 @@ module Clearance
|
|
6
6
|
def self.included(controller_test)
|
7
7
|
controller_test.class_eval do
|
8
8
|
|
9
|
-
should_filter_params :
|
9
|
+
should_filter_params :token
|
10
10
|
|
11
11
|
context "Given a user whose email has not been confirmed" do
|
12
12
|
setup { @user = Factory(:registered_user) }
|
13
13
|
|
14
|
-
context "on GET to #new with correct id and
|
14
|
+
context "on GET to #new with correct id and token" do
|
15
15
|
setup do
|
16
|
-
get :new, :user_id => @user.to_param, :
|
16
|
+
get :new, :user_id => @user.to_param, :token => @user.token
|
17
17
|
end
|
18
18
|
|
19
19
|
should_set_the_flash_to /confirmed email/i
|
@@ -22,12 +22,12 @@ module Clearance
|
|
22
22
|
should_redirect_to_url_after_create
|
23
23
|
end
|
24
24
|
|
25
|
-
context "on GET to #new with incorrect
|
25
|
+
context "on GET to #new with incorrect token" do
|
26
26
|
setup do
|
27
|
-
|
28
|
-
assert_not_equal
|
27
|
+
token = ""
|
28
|
+
assert_not_equal token, @user.token
|
29
29
|
|
30
|
-
get :new, :user_id => @user.to_param, :
|
30
|
+
get :new, :user_id => @user.to_param, :token => token
|
31
31
|
end
|
32
32
|
|
33
33
|
should_respond_with :not_found
|
@@ -9,8 +9,11 @@ module Clearance
|
|
9
9
|
should_route :get, '/users/1/password/edit',
|
10
10
|
:action => 'edit', :user_id => '1'
|
11
11
|
|
12
|
-
context "with a user" do
|
13
|
-
setup
|
12
|
+
context "with a confirmed user" do
|
13
|
+
setup do
|
14
|
+
@user = Factory(:registered_user)
|
15
|
+
@user.confirm_email!
|
16
|
+
end
|
14
17
|
|
15
18
|
context 'A GET to #new' do
|
16
19
|
setup { get :new, :user_id => @user.to_param }
|
@@ -23,15 +26,10 @@ module Clearance
|
|
23
26
|
context "with an existing user's email address" do
|
24
27
|
setup do
|
25
28
|
ActionMailer::Base.deliveries.clear
|
26
|
-
|
27
29
|
post :create, :password => { :email => @user.email }
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
|
-
assert_sent_email do |email|
|
32
|
-
email.subject =~ /change your password/i
|
33
|
-
end
|
34
|
-
end
|
32
|
+
should_send_the_change_your_password_email
|
35
33
|
|
36
34
|
should "set a :notice flash with the user email address" do
|
37
35
|
assert_match /#{@user.email}/, flash[:notice]
|
@@ -48,11 +46,9 @@ module Clearance
|
|
48
46
|
|
49
47
|
post :create, :password => { :email => email }
|
50
48
|
end
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
|
49
|
+
|
50
|
+
should_not_send_the_change_your_password_email
|
51
|
+
|
56
52
|
should "set a :notice flash" do
|
57
53
|
assert_not_nil flash.now[:notice]
|
58
54
|
end
|
@@ -60,112 +56,120 @@ module Clearance
|
|
60
56
|
should_render_template "new"
|
61
57
|
end
|
62
58
|
end
|
59
|
+
|
60
|
+
context 'who requested password recovery' do
|
61
|
+
setup { @user.forgot_password! }
|
62
|
+
|
63
|
+
context "A GET to #edit" do
|
64
|
+
context "with an existing user's id and token" do
|
65
|
+
setup do
|
66
|
+
get :edit, :user_id => @user.to_param, :token => @user.token
|
67
|
+
end
|
63
68
|
|
64
|
-
|
65
|
-
|
66
|
-
setup do
|
67
|
-
get :edit,
|
68
|
-
:user_id => @user.to_param,
|
69
|
-
:password => @user.encrypted_password,
|
70
|
-
:email => @user.email
|
71
|
-
end
|
72
|
-
|
73
|
-
should "find the user with the given id and password" do
|
74
|
-
assert_equal @user, assigns(:user)
|
75
|
-
end
|
76
|
-
|
77
|
-
should_respond_with :success
|
78
|
-
should_render_template "edit"
|
79
|
-
|
80
|
-
should "have a form for the user's email, password, and password confirm" do
|
81
|
-
update_path = ERB::Util.h(user_password_path(@user,
|
82
|
-
:password => @user.encrypted_password,
|
83
|
-
:email => @user.email))
|
84
|
-
|
85
|
-
assert_select 'form[action=?]', update_path do
|
86
|
-
assert_select 'input[name=_method][value=?]', 'put'
|
87
|
-
assert_select 'input[name=?]', 'user[password]'
|
88
|
-
assert_select 'input[name=?]', 'user[password_confirmation]'
|
69
|
+
should "find the user with the given id and token" do
|
70
|
+
assert_equal @user, assigns(:user)
|
89
71
|
end
|
90
|
-
end
|
91
|
-
end
|
92
72
|
|
93
|
-
|
94
|
-
|
95
|
-
|
73
|
+
should_respond_with :success
|
74
|
+
should_render_template "edit"
|
75
|
+
should_display_a_password_update_form
|
96
76
|
end
|
97
77
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
context "A PUT to #update" do
|
104
|
-
context "with an existing user's id but not password" do
|
105
|
-
setup do
|
106
|
-
put :update, :user_id => @user.to_param, :password => ""
|
107
|
-
end
|
78
|
+
context "with an existing user's id but not token" do
|
79
|
+
setup do
|
80
|
+
get :edit, :user_id => @user.to_param, :token => ""
|
81
|
+
end
|
108
82
|
|
109
|
-
|
110
|
-
|
83
|
+
should_respond_with :not_found
|
84
|
+
should_render_nothing
|
111
85
|
end
|
112
|
-
|
113
|
-
should_not_be_signed_in
|
114
|
-
should_respond_with :not_found
|
115
|
-
should_render_nothing
|
116
86
|
end
|
117
87
|
|
118
|
-
context "
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
88
|
+
context "A PUT to #update" do
|
89
|
+
context "with a matching password and password confirmation" do
|
90
|
+
setup do
|
91
|
+
new_password = "new_password"
|
92
|
+
@encrypted_new_password = @user.encrypt(new_password)
|
93
|
+
assert_not_equal @encrypted_new_password, @user.encrypted_password
|
94
|
+
|
95
|
+
put(:update,
|
96
|
+
:user_id => @user,
|
97
|
+
:token => @user.token,
|
98
|
+
:user => {
|
99
|
+
:password => new_password,
|
100
|
+
:password_confirmation => new_password
|
101
|
+
})
|
102
|
+
@user.reload
|
103
|
+
end
|
134
104
|
|
135
|
-
|
136
|
-
|
137
|
-
|
105
|
+
should "update the user's password" do
|
106
|
+
assert_equal @encrypted_new_password, @user.encrypted_password
|
107
|
+
end
|
108
|
+
|
109
|
+
should "clear the token" do
|
110
|
+
assert_nil @user.token
|
111
|
+
end
|
112
|
+
|
113
|
+
should_be_signed_in_as { @user }
|
114
|
+
should_redirect_to_url_after_update
|
115
|
+
end
|
116
|
+
|
117
|
+
context "with password but blank password confirmation" do
|
118
|
+
setup do
|
119
|
+
new_password = "new_password"
|
120
|
+
@encrypted_new_password = @user.encrypt(new_password)
|
121
|
+
|
122
|
+
put(:update,
|
123
|
+
:user_id => @user.to_param,
|
124
|
+
:token => @user.token,
|
125
|
+
:user => {
|
126
|
+
:password => new_password,
|
127
|
+
:password_confirmation => ''
|
128
|
+
})
|
129
|
+
@user.reload
|
130
|
+
end
|
138
131
|
|
139
|
-
|
140
|
-
|
141
|
-
|
132
|
+
should "not update the user's password" do
|
133
|
+
assert_not_equal @encrypted_new_password, @user.encrypted_password
|
134
|
+
end
|
135
|
+
|
136
|
+
should "not clear the token" do
|
137
|
+
assert_not_nil @user.token
|
138
|
+
end
|
142
139
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
put(:update,
|
149
|
-
:user_id => @user.to_param,
|
150
|
-
:password => @user.encrypted_password,
|
151
|
-
:user => {
|
152
|
-
:password => new_password,
|
153
|
-
:password_confirmation => ''
|
154
|
-
})
|
155
|
-
@user.reload
|
140
|
+
should_not_be_signed_in
|
141
|
+
should_respond_with :success
|
142
|
+
should_render_template :edit
|
143
|
+
|
144
|
+
should_display_a_password_update_form
|
156
145
|
end
|
146
|
+
|
147
|
+
context "with an existing user's id but not token" do
|
148
|
+
setup do
|
149
|
+
new_password = "new_password"
|
150
|
+
@encrypted_new_password = @user.encrypt(new_password)
|
151
|
+
put(:update,
|
152
|
+
:user_id => @user.to_param,
|
153
|
+
:token => "",
|
154
|
+
:user => {
|
155
|
+
:password => new_password,
|
156
|
+
:password => new_password
|
157
|
+
})
|
158
|
+
end
|
157
159
|
|
158
|
-
|
159
|
-
|
160
|
-
|
160
|
+
should "not update the user's password" do
|
161
|
+
assert_not_equal @encrypted_new_password, @user.encrypted_password
|
162
|
+
end
|
161
163
|
|
162
|
-
|
163
|
-
|
164
|
-
|
164
|
+
should_not_be_signed_in
|
165
|
+
should_respond_with :not_found
|
166
|
+
should_render_nothing
|
167
|
+
end
|
165
168
|
end
|
169
|
+
|
166
170
|
end
|
167
|
-
|
168
|
-
|
171
|
+
|
172
|
+
end
|
169
173
|
end
|
170
174
|
end
|
171
175
|
|
@@ -15,19 +15,7 @@ module Clearance
|
|
15
15
|
should_render_template :new
|
16
16
|
should_not_set_the_flash
|
17
17
|
|
18
|
-
|
19
|
-
assert_select "form[action=#{session_path}][method=post]",
|
20
|
-
true, "There must be a form to sign in" do
|
21
|
-
assert_select "input[type=text][name=?]",
|
22
|
-
"session[email]", true, "There must be an email field"
|
23
|
-
assert_select "input[type=password][name=?]",
|
24
|
-
"session[password]", true, "There must be a password field"
|
25
|
-
assert_select "input[type=checkbox][name=?]",
|
26
|
-
"session[remember_me]", true, "There must be a 'remember me' check box"
|
27
|
-
assert_select "input[type=submit]", true,
|
28
|
-
"There must be a submit button"
|
29
|
-
end
|
30
|
-
end
|
18
|
+
should_display_a_sign_in_form
|
31
19
|
end
|
32
20
|
|
33
21
|
context "Given a registered user" do
|
@@ -46,7 +34,10 @@ module Clearance
|
|
46
34
|
end
|
47
35
|
|
48
36
|
context "Given an email confirmed user" do
|
49
|
-
setup
|
37
|
+
setup do
|
38
|
+
@user = Factory(:registered_user)
|
39
|
+
@user.confirm_email!
|
40
|
+
end
|
50
41
|
|
51
42
|
context "a POST to #create with good credentials" do
|
52
43
|
setup do
|
@@ -88,9 +79,9 @@ module Clearance
|
|
88
79
|
assert ! cookies['remember_token'].empty?
|
89
80
|
end
|
90
81
|
|
91
|
-
should 'set the
|
92
|
-
assert_not_nil @user.reload.
|
93
|
-
assert_not_nil @user.reload.
|
82
|
+
should 'set the token in users table' do
|
83
|
+
assert_not_nil @user.reload.token
|
84
|
+
assert_not_nil @user.reload.token_expires_at
|
94
85
|
end
|
95
86
|
end
|
96
87
|
|
@@ -111,8 +102,8 @@ module Clearance
|
|
111
102
|
end
|
112
103
|
|
113
104
|
should 'not set the remember me token in users table' do
|
114
|
-
assert_nil @user.reload.
|
115
|
-
assert_nil @user.reload.
|
105
|
+
assert_nil @user.reload.token
|
106
|
+
assert_nil @user.reload.token_expires_at
|
116
107
|
end
|
117
108
|
end
|
118
109
|
|
@@ -133,7 +124,7 @@ module Clearance
|
|
133
124
|
post :create, :session => {
|
134
125
|
:email => @user.email,
|
135
126
|
:password => @user.password },
|
136
|
-
|
127
|
+
:return_to => '/url_in_the_request'
|
137
128
|
end
|
138
129
|
|
139
130
|
should_redirect_to "'/url_in_the_request'"
|
@@ -145,7 +136,7 @@ module Clearance
|
|
145
136
|
post :create, :session => {
|
146
137
|
:email => @user.email,
|
147
138
|
:password => @user.password },
|
148
|
-
|
139
|
+
:return_to => '/url_in_the_request'
|
149
140
|
end
|
150
141
|
|
151
142
|
should_redirect_to "'/url_in_the_session'"
|
@@ -170,7 +161,7 @@ module Clearance
|
|
170
161
|
|
171
162
|
context 'a DELETE to #destroy with a cookie' do
|
172
163
|
setup do
|
173
|
-
cookies['remember_token'] = CGI::Cookie.new
|
164
|
+
cookies['remember_token'] = CGI::Cookie.new('token', 'value')
|
174
165
|
delete :destroy
|
175
166
|
end
|
176
167
|
|
@@ -179,8 +170,8 @@ module Clearance
|
|
179
170
|
end
|
180
171
|
|
181
172
|
should 'delete the remember me token in users table' do
|
182
|
-
assert_nil @user.reload.
|
183
|
-
assert_nil @user.reload.
|
173
|
+
assert_nil @user.reload.token
|
174
|
+
assert_nil @user.reload.token_expires_at
|
184
175
|
end
|
185
176
|
end
|
186
177
|
end
|
@@ -16,19 +16,7 @@ module Clearance
|
|
16
16
|
should_render_template :new
|
17
17
|
should_not_set_the_flash
|
18
18
|
|
19
|
-
|
20
|
-
assert_select "form[action=#{users_path}][method=post]",
|
21
|
-
true, "There must be a form to register" do
|
22
|
-
assert_select "input[type=text][name=?]",
|
23
|
-
"user[email]", true, "There must be an email field"
|
24
|
-
assert_select "input[type=password][name=?]",
|
25
|
-
"user[password]", true, "There must be a password field"
|
26
|
-
assert_select "input[type=password][name=?]",
|
27
|
-
"user[password_confirmation]", true, "There must be a password confirmation field"
|
28
|
-
assert_select "input[type=submit]", true,
|
29
|
-
"There must be a submit button"
|
30
|
-
end
|
31
|
-
end
|
19
|
+
should_display_a_registration_form
|
32
20
|
end
|
33
21
|
|
34
22
|
context "Given email parameter when getting new User view" do
|
@@ -18,7 +18,7 @@ module Clearance
|
|
18
18
|
|
19
19
|
should "contain a link to edit the user's password" do
|
20
20
|
host = ActionMailer::Base.default_url_options[:host]
|
21
|
-
regexp = %r{http://#{host}/users/#{@user.id}/password/edit\?
|
21
|
+
regexp = %r{http://#{host}/users/#{@user.id}/password/edit\?token=#{@user.token}}
|
22
22
|
assert_match regexp, @email.body
|
23
23
|
end
|
24
24
|
|
@@ -51,7 +51,7 @@ module Clearance
|
|
51
51
|
|
52
52
|
should "contain a link to confirm the user's account" do
|
53
53
|
host = ActionMailer::Base.default_url_options[:host]
|
54
|
-
regexp = %r{http://#{host}/users/#{@user.id}/confirmation/new\?
|
54
|
+
regexp = %r{http://#{host}/users/#{@user.id}/confirmation/new\?token=#{@user.token}}
|
55
55
|
assert_match regexp, @email.body
|
56
56
|
end
|
57
57
|
end
|
@@ -8,7 +8,7 @@ module Clearance
|
|
8
8
|
|
9
9
|
should_protect_attributes :email_confirmed,
|
10
10
|
:salt, :encrypted_password,
|
11
|
-
:
|
11
|
+
:token, :token_expires_at
|
12
12
|
|
13
13
|
# registering
|
14
14
|
|
@@ -25,6 +25,11 @@ module Clearance
|
|
25
25
|
assert_not_nil Factory(:registered_user).salt
|
26
26
|
end
|
27
27
|
|
28
|
+
should "initialize token witout expiry date" do
|
29
|
+
assert_not_nil Factory(:registered_user).token
|
30
|
+
assert_nil Factory(:registered_user).token_expires_at
|
31
|
+
end
|
32
|
+
|
28
33
|
context "encrypt password" do
|
29
34
|
setup do
|
30
35
|
@salt = "salt"
|
@@ -72,6 +77,10 @@ module Clearance
|
|
72
77
|
should "have confirmed their email" do
|
73
78
|
assert @user.email_confirmed?
|
74
79
|
end
|
80
|
+
|
81
|
+
should "reset token" do
|
82
|
+
assert_nil @user.token
|
83
|
+
end
|
75
84
|
end
|
76
85
|
end
|
77
86
|
|
@@ -101,39 +110,44 @@ module Clearance
|
|
101
110
|
|
102
111
|
# remember me
|
103
112
|
|
104
|
-
context "When
|
113
|
+
context "When authenticating with remember_me!" do
|
105
114
|
setup do
|
106
|
-
@user = Factory(:
|
107
|
-
|
108
|
-
assert_nil @user.
|
115
|
+
@user = Factory(:email_confirmed_user)
|
116
|
+
@token = @user.token
|
117
|
+
assert_nil @user.token_expires_at
|
109
118
|
@user.remember_me!
|
110
119
|
end
|
111
120
|
|
112
121
|
should "set the remember token and expiration date" do
|
113
|
-
|
114
|
-
assert_not_nil @user.
|
122
|
+
assert_not_equal @token, @user.token
|
123
|
+
assert_not_nil @user.token_expires_at
|
115
124
|
end
|
116
125
|
|
117
126
|
should "remember user when token expires in the future" do
|
118
|
-
@user.update_attribute :
|
127
|
+
@user.update_attribute :token_expires_at,
|
119
128
|
2.weeks.from_now.utc
|
120
129
|
assert @user.remember?
|
121
130
|
end
|
122
131
|
|
123
132
|
should "not remember user when token has already expired" do
|
124
|
-
@user.update_attribute :
|
133
|
+
@user.update_attribute :token_expires_at,
|
125
134
|
2.weeks.ago.utc
|
126
135
|
assert ! @user.remember?
|
127
136
|
end
|
128
137
|
|
138
|
+
should "not remember user when token expiry date is not set" do
|
139
|
+
@user.update_attribute :token_expires_at, nil
|
140
|
+
assert ! @user.remember?
|
141
|
+
end
|
142
|
+
|
129
143
|
# logging out
|
130
144
|
|
131
145
|
context "forget_me!" do
|
132
146
|
setup { @user.forget_me! }
|
133
147
|
|
134
148
|
should "unset the remember token and expiration date" do
|
135
|
-
assert_nil @user.
|
136
|
-
assert_nil @user.
|
149
|
+
assert_nil @user.token
|
150
|
+
assert_nil @user.token_expires_at
|
137
151
|
end
|
138
152
|
|
139
153
|
should "not remember user" do
|
@@ -157,6 +171,54 @@ module Clearance
|
|
157
171
|
should_change "@user.encrypted_password"
|
158
172
|
end
|
159
173
|
end
|
174
|
+
|
175
|
+
# recovering forgotten password
|
176
|
+
|
177
|
+
context "An email confirmed user" do
|
178
|
+
setup do
|
179
|
+
@user = Factory(:registered_user)
|
180
|
+
@user.confirm_email!
|
181
|
+
end
|
182
|
+
|
183
|
+
context "who forgets password" do
|
184
|
+
setup do
|
185
|
+
assert_nil @user.token
|
186
|
+
@user.forgot_password!
|
187
|
+
end
|
188
|
+
should "generate token" do
|
189
|
+
assert_not_nil @user.token
|
190
|
+
end
|
191
|
+
|
192
|
+
context "and then updates password" do
|
193
|
+
context 'with a valid new password and confirmation' do
|
194
|
+
setup do
|
195
|
+
@user.update_password(
|
196
|
+
:password => "new_password",
|
197
|
+
:password_confirmation => "new_password"
|
198
|
+
)
|
199
|
+
end
|
200
|
+
|
201
|
+
should_change "@user.encrypted_password"
|
202
|
+
should "clear token" do
|
203
|
+
assert_nil @user.token
|
204
|
+
end
|
205
|
+
end
|
206
|
+
context 'with a password without a confirmation' do
|
207
|
+
setup do
|
208
|
+
@user.update_password(
|
209
|
+
:password => "new_password",
|
210
|
+
:password_confirmation => ""
|
211
|
+
)
|
212
|
+
end
|
213
|
+
should "not clear token" do
|
214
|
+
assert_not_nil @user.token
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
end
|
160
222
|
|
161
223
|
end
|
162
224
|
end
|
data/shoulda_macros/clearance.rb
CHANGED
@@ -143,6 +143,78 @@ module Clearance
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
+
# EMAILS
|
147
|
+
|
148
|
+
def should_send_the_change_your_password_email
|
149
|
+
should "generate a token for the change your password email" do
|
150
|
+
assert_not_nil @user.reload.token
|
151
|
+
end
|
152
|
+
|
153
|
+
should "send the change your password email" do
|
154
|
+
assert_sent_email do |email|
|
155
|
+
email.subject =~ /change your password/i
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def should_not_send_the_change_your_password_email
|
161
|
+
should "generate a token for the change your password email" do
|
162
|
+
assert_nil @user.reload.token
|
163
|
+
end
|
164
|
+
|
165
|
+
should "not send a password reminder email" do
|
166
|
+
assert ActionMailer::Base.deliveries.empty?
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# FORMS
|
172
|
+
|
173
|
+
def should_display_a_password_update_form
|
174
|
+
should "have a form for the user's token, password, and password confirm" do
|
175
|
+
update_path = ERB::Util.h(
|
176
|
+
user_password_path(@user, :token => @user.token)
|
177
|
+
)
|
178
|
+
|
179
|
+
assert_select 'form[action=?]', update_path do
|
180
|
+
assert_select 'input[name=_method][value=?]', 'put'
|
181
|
+
assert_select 'input[name=?]', 'user[password]'
|
182
|
+
assert_select 'input[name=?]', 'user[password_confirmation]'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def should_display_a_registration_form
|
188
|
+
should "display a form to register" do
|
189
|
+
assert_select "form[action=#{users_path}][method=post]",
|
190
|
+
true, "There must be a form to register" do
|
191
|
+
assert_select "input[type=text][name=?]",
|
192
|
+
"user[email]", true, "There must be an email field"
|
193
|
+
assert_select "input[type=password][name=?]",
|
194
|
+
"user[password]", true, "There must be a password field"
|
195
|
+
assert_select "input[type=password][name=?]",
|
196
|
+
"user[password_confirmation]", true, "There must be a password confirmation field"
|
197
|
+
assert_select "input[type=submit]", true,
|
198
|
+
"There must be a submit button"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def should_display_a_sign_in_form
|
204
|
+
should 'display a "sign in" form' do
|
205
|
+
assert_select "form[action=#{session_path}][method=post]",
|
206
|
+
true, "There must be a form to sign in" do
|
207
|
+
assert_select "input[type=text][name=?]",
|
208
|
+
"session[email]", true, "There must be an email field"
|
209
|
+
assert_select "input[type=password][name=?]",
|
210
|
+
"session[password]", true, "There must be a password field"
|
211
|
+
assert_select "input[type=checkbox][name=?]",
|
212
|
+
"session[remember_me]", true, "There must be a 'remember me' check box"
|
213
|
+
assert_select "input[type=submit]", true,
|
214
|
+
"There must be a submit button"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
146
218
|
end
|
147
219
|
end
|
148
220
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thoughtbot-clearance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thoughtbot, inc.
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2009-01-
|
18
|
+
date: 2009-01-27 21:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -28,26 +28,30 @@ extensions: []
|
|
28
28
|
extra_rdoc_files: []
|
29
29
|
|
30
30
|
files:
|
31
|
+
- LICENSE
|
31
32
|
- Rakefile
|
32
33
|
- README.textile
|
33
|
-
- LICENSE
|
34
34
|
- TODO.textile
|
35
35
|
- generators/clearance
|
36
|
+
- generators/clearance/clearance_generator.rb
|
37
|
+
- generators/clearance/lib
|
38
|
+
- generators/clearance/lib/insert_commands.rb
|
39
|
+
- generators/clearance/lib/rake_commands.rb
|
36
40
|
- generators/clearance/templates
|
37
|
-
- generators/clearance/templates/README
|
38
|
-
- generators/clearance/templates/test
|
39
|
-
- generators/clearance/templates/test/factories
|
40
|
-
- generators/clearance/templates/test/factories/clearance.rb
|
41
|
-
- generators/clearance/templates/test/functional
|
42
|
-
- generators/clearance/templates/test/functional/confirmations_controller_test.rb
|
43
|
-
- generators/clearance/templates/test/functional/passwords_controller_test.rb
|
44
|
-
- generators/clearance/templates/test/functional/sessions_controller_test.rb
|
45
|
-
- generators/clearance/templates/test/functional/users_controller_test.rb
|
46
|
-
- generators/clearance/templates/test/unit
|
47
|
-
- generators/clearance/templates/test/unit/clearance_mailer_test.rb
|
48
|
-
- generators/clearance/templates/test/unit/user_test.rb
|
49
41
|
- generators/clearance/templates/app
|
42
|
+
- generators/clearance/templates/app/controllers
|
43
|
+
- generators/clearance/templates/app/controllers/application.rb
|
44
|
+
- generators/clearance/templates/app/controllers/confirmations_controller.rb
|
45
|
+
- generators/clearance/templates/app/controllers/passwords_controller.rb
|
46
|
+
- generators/clearance/templates/app/controllers/sessions_controller.rb
|
47
|
+
- generators/clearance/templates/app/controllers/users_controller.rb
|
48
|
+
- generators/clearance/templates/app/models
|
49
|
+
- generators/clearance/templates/app/models/clearance_mailer.rb
|
50
|
+
- generators/clearance/templates/app/models/user.rb
|
50
51
|
- generators/clearance/templates/app/views
|
52
|
+
- generators/clearance/templates/app/views/clearance_mailer
|
53
|
+
- generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb
|
54
|
+
- generators/clearance/templates/app/views/clearance_mailer/confirmation.html.erb
|
51
55
|
- generators/clearance/templates/app/views/passwords
|
52
56
|
- generators/clearance/templates/app/views/passwords/edit.html.erb
|
53
57
|
- generators/clearance/templates/app/views/passwords/new.html.erb
|
@@ -57,48 +61,44 @@ files:
|
|
57
61
|
- generators/clearance/templates/app/views/users/_form.html.erb
|
58
62
|
- generators/clearance/templates/app/views/users/edit.html.erb
|
59
63
|
- generators/clearance/templates/app/views/users/new.html.erb
|
60
|
-
- generators/clearance/templates/app/views/clearance_mailer
|
61
|
-
- generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb
|
62
|
-
- generators/clearance/templates/app/views/clearance_mailer/confirmation.html.erb
|
63
|
-
- generators/clearance/templates/app/models
|
64
|
-
- generators/clearance/templates/app/models/user.rb
|
65
|
-
- generators/clearance/templates/app/models/clearance_mailer.rb
|
66
|
-
- generators/clearance/templates/app/controllers
|
67
|
-
- generators/clearance/templates/app/controllers/application.rb
|
68
|
-
- generators/clearance/templates/app/controllers/passwords_controller.rb
|
69
|
-
- generators/clearance/templates/app/controllers/users_controller.rb
|
70
|
-
- generators/clearance/templates/app/controllers/sessions_controller.rb
|
71
|
-
- generators/clearance/templates/app/controllers/confirmations_controller.rb
|
72
64
|
- generators/clearance/templates/db
|
73
65
|
- generators/clearance/templates/db/migrate
|
74
66
|
- generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb
|
75
67
|
- generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb
|
76
|
-
- generators/clearance/
|
77
|
-
- generators/clearance/
|
78
|
-
- generators/clearance/
|
68
|
+
- generators/clearance/templates/README
|
69
|
+
- generators/clearance/templates/test
|
70
|
+
- generators/clearance/templates/test/factories
|
71
|
+
- generators/clearance/templates/test/factories/clearance.rb
|
72
|
+
- generators/clearance/templates/test/functional
|
73
|
+
- generators/clearance/templates/test/functional/confirmations_controller_test.rb
|
74
|
+
- generators/clearance/templates/test/functional/passwords_controller_test.rb
|
75
|
+
- generators/clearance/templates/test/functional/sessions_controller_test.rb
|
76
|
+
- generators/clearance/templates/test/functional/users_controller_test.rb
|
77
|
+
- generators/clearance/templates/test/unit
|
78
|
+
- generators/clearance/templates/test/unit/clearance_mailer_test.rb
|
79
|
+
- generators/clearance/templates/test/unit/user_test.rb
|
79
80
|
- generators/clearance/USAGE
|
80
|
-
- generators/clearance/clearance_generator.rb
|
81
81
|
- lib/clearance
|
82
|
+
- lib/clearance/app
|
83
|
+
- lib/clearance/app/controllers
|
84
|
+
- lib/clearance/app/controllers/application_controller.rb
|
85
|
+
- lib/clearance/app/controllers/confirmations_controller.rb
|
86
|
+
- lib/clearance/app/controllers/passwords_controller.rb
|
87
|
+
- lib/clearance/app/controllers/sessions_controller.rb
|
88
|
+
- lib/clearance/app/controllers/users_controller.rb
|
89
|
+
- lib/clearance/app/models
|
90
|
+
- lib/clearance/app/models/clearance_mailer.rb
|
91
|
+
- lib/clearance/app/models/user.rb
|
82
92
|
- lib/clearance/test
|
83
|
-
- lib/clearance/test/test_helper.rb
|
84
93
|
- lib/clearance/test/functional
|
85
94
|
- lib/clearance/test/functional/confirmations_controller_test.rb
|
86
95
|
- lib/clearance/test/functional/passwords_controller_test.rb
|
87
96
|
- lib/clearance/test/functional/sessions_controller_test.rb
|
88
97
|
- lib/clearance/test/functional/users_controller_test.rb
|
98
|
+
- lib/clearance/test/test_helper.rb
|
89
99
|
- lib/clearance/test/unit
|
90
100
|
- lib/clearance/test/unit/clearance_mailer_test.rb
|
91
101
|
- lib/clearance/test/unit/user_test.rb
|
92
|
-
- lib/clearance/app
|
93
|
-
- lib/clearance/app/models
|
94
|
-
- lib/clearance/app/models/user.rb
|
95
|
-
- lib/clearance/app/models/clearance_mailer.rb
|
96
|
-
- lib/clearance/app/controllers
|
97
|
-
- lib/clearance/app/controllers/application_controller.rb
|
98
|
-
- lib/clearance/app/controllers/passwords_controller.rb
|
99
|
-
- lib/clearance/app/controllers/users_controller.rb
|
100
|
-
- lib/clearance/app/controllers/sessions_controller.rb
|
101
|
-
- lib/clearance/app/controllers/confirmations_controller.rb
|
102
102
|
- lib/clearance.rb
|
103
103
|
- shoulda_macros/clearance.rb
|
104
104
|
- rails/init.rb
|