thoughtbot-clearance 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|