thoughtbot-clearance 0.3.8 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +17 -16
- data/Rakefile +8 -7
- data/TODO.textile +3 -3
- data/generators/clearance/clearance_generator.rb +1 -1
- data/generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb +1 -1
- data/generators/clearance/templates/app/views/passwords/edit.html.erb +1 -1
- data/generators/clearance/templates/app/views/sessions/new.html.erb +2 -2
- data/generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb +3 -3
- data/generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb +14 -13
- data/generators/clearance/templates/test/factories/clearance.rb +16 -0
- data/lib/clearance/app/controllers/application_controller.rb +26 -14
- data/lib/clearance/app/controllers/confirmations_controller.rb +6 -3
- data/lib/clearance/app/controllers/passwords_controller.rb +15 -9
- data/lib/clearance/app/controllers/sessions_controller.rb +21 -17
- data/lib/clearance/app/controllers/users_controller.rb +4 -3
- data/lib/clearance/app/models/clearance_mailer.rb +1 -1
- data/lib/clearance/app/models/user.rb +15 -16
- data/lib/clearance/test/functional/confirmations_controller_test.rb +18 -30
- data/lib/clearance/test/functional/passwords_controller_test.rb +27 -45
- data/lib/clearance/test/functional/sessions_controller_test.rb +23 -27
- data/lib/clearance/test/functional/users_controller_test.rb +38 -28
- data/lib/clearance/test/test_helper.rb +7 -2
- data/lib/clearance/test/unit/clearance_mailer_test.rb +7 -5
- data/lib/clearance/test/unit/user_test.rb +107 -138
- data/shoulda_macros/clearance.rb +134 -6
- metadata +7 -3
- data/generators/clearance/templates/test/factories/clearance_user.rb +0 -9
@@ -5,8 +5,8 @@ module Clearance
|
|
5
5
|
|
6
6
|
def self.included(controller)
|
7
7
|
controller.class_eval do
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
before_filter :redirect_to_root, :only => [:new, :create], :if => :signed_in?
|
10
10
|
filter_parameter_logging :password
|
11
11
|
|
12
12
|
def new
|
@@ -17,7 +17,8 @@ module Clearance
|
|
17
17
|
@user = User.new params[:user]
|
18
18
|
if @user.save
|
19
19
|
ClearanceMailer.deliver_confirmation @user
|
20
|
-
flash[:notice] = "You will receive an email within the next few minutes.
|
20
|
+
flash[:notice] = "You will receive an email within the next few minutes. " <<
|
21
|
+
"It contains instructions for you to confirm your account."
|
21
22
|
redirect_to url_after_create
|
22
23
|
else
|
23
24
|
render :action => "new"
|
@@ -17,27 +17,22 @@ 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
|
20
|
+
before_save :initialize_salt, :encrypt_password, :downcase_email
|
21
21
|
|
22
22
|
def self.authenticate(email, password)
|
23
23
|
user = find(:first, :conditions => ['LOWER(email) = ?', email.to_s.downcase])
|
24
24
|
user && user.authenticated?(password) ? user : nil
|
25
25
|
end
|
26
|
-
|
27
|
-
def email=(value)
|
28
|
-
value = value.to_s.downcase if value
|
29
|
-
write_attribute(:email, value.to_s)
|
30
|
-
end
|
31
26
|
|
32
27
|
def authenticated?(password)
|
33
|
-
|
28
|
+
encrypted_password == encrypt(password)
|
34
29
|
end
|
35
30
|
|
36
|
-
def encrypt(
|
37
|
-
Digest::SHA512.hexdigest
|
31
|
+
def encrypt(string)
|
32
|
+
Digest::SHA512.hexdigest("--#{salt}--#{string}--")
|
38
33
|
end
|
39
34
|
|
40
|
-
def
|
35
|
+
def remember?
|
41
36
|
remember_token_expires_at && Time.now.utc < remember_token_expires_at
|
42
37
|
end
|
43
38
|
|
@@ -48,7 +43,7 @@ module Clearance
|
|
48
43
|
def remember_me_until(time)
|
49
44
|
self.update_attribute :remember_token_expires_at, time
|
50
45
|
self.update_attribute :remember_token,
|
51
|
-
encrypt("
|
46
|
+
encrypt("--#{remember_token_expires_at}--#{password}--")
|
52
47
|
end
|
53
48
|
|
54
49
|
def forget_me!
|
@@ -56,25 +51,29 @@ module Clearance
|
|
56
51
|
self.update_attribute :remember_token, nil
|
57
52
|
end
|
58
53
|
|
59
|
-
def
|
60
|
-
self.update_attribute :
|
54
|
+
def confirm_email!
|
55
|
+
self.update_attribute :email_confirmed, true
|
61
56
|
end
|
62
57
|
|
63
58
|
protected
|
64
59
|
|
65
60
|
def initialize_salt
|
66
61
|
if new_record?
|
67
|
-
self.salt =
|
62
|
+
self.salt = encrypt("--#{Time.now.utc.to_s}--#{password}--")
|
68
63
|
end
|
69
64
|
end
|
70
65
|
|
71
66
|
def encrypt_password
|
72
67
|
return if password.blank?
|
73
|
-
self.
|
68
|
+
self.encrypted_password = encrypt(password)
|
74
69
|
end
|
75
70
|
|
76
71
|
def password_required?
|
77
|
-
|
72
|
+
encrypted_password.blank? || !password.blank?
|
73
|
+
end
|
74
|
+
|
75
|
+
def downcase_email
|
76
|
+
self.email = email.to_s.downcase
|
78
77
|
end
|
79
78
|
|
80
79
|
end
|
@@ -3,48 +3,36 @@ module Clearance
|
|
3
3
|
module Functional
|
4
4
|
module ConfirmationsControllerTest
|
5
5
|
|
6
|
-
def self.included(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
def self.included(controller_test)
|
7
|
+
controller_test.class_eval do
|
8
|
+
|
9
|
+
should_filter_params :salt
|
10
|
+
|
11
|
+
context "Given a user whose email has not been confirmed" do
|
12
|
+
setup { @user = Factory(:registered_user) }
|
13
|
+
|
14
|
+
context "on GET to #new with correct id and salt" do
|
11
15
|
setup do
|
12
|
-
@user = Factory :clearance_user
|
13
16
|
get :new, :user_id => @user.to_param, :salt => @user.salt
|
14
17
|
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
should 'confirm the User record with the given id' do
|
21
|
-
assert assigns(:user).confirmed?
|
22
|
-
end
|
23
|
-
|
24
|
-
should 'log the User in' do
|
25
|
-
assert_equal @user.id, session[:user_id]
|
26
|
-
end
|
27
|
-
|
28
|
-
should_redirect_to "@controller.send(:url_after_create)"
|
19
|
+
should_be_signed_in_and_email_confirmed_as { @user }
|
20
|
+
should_redirect_to_url_after_create
|
29
21
|
end
|
30
|
-
|
31
|
-
context "
|
22
|
+
|
23
|
+
context "on GET to #new with incorrect salt" do
|
32
24
|
setup do
|
33
|
-
|
34
|
-
salt
|
35
|
-
assert_not_equal salt, user.salt
|
25
|
+
salt = ""
|
26
|
+
assert_not_equal salt, @user.salt
|
36
27
|
|
37
|
-
get :new, :user_id => user.to_param, :salt =>
|
28
|
+
get :new, :user_id => @user.to_param, :salt => salt
|
38
29
|
end
|
39
30
|
|
40
31
|
should_respond_with :not_found
|
41
|
-
|
42
|
-
should 'render nothing' do
|
43
|
-
assert @response.body.blank?
|
44
|
-
end
|
32
|
+
should_render_nothing
|
45
33
|
end
|
46
34
|
end
|
47
|
-
|
35
|
+
|
48
36
|
end
|
49
37
|
end
|
50
38
|
|
@@ -3,13 +3,14 @@ module Clearance
|
|
3
3
|
module Functional
|
4
4
|
module PasswordsControllerTest
|
5
5
|
|
6
|
-
def self.included(
|
7
|
-
|
6
|
+
def self.included(controller_test)
|
7
|
+
controller_test.class_eval do
|
8
8
|
|
9
|
-
should_route :get, '/users/1/password/edit',
|
9
|
+
should_route :get, '/users/1/password/edit',
|
10
|
+
:action => 'edit', :user_id => '1'
|
10
11
|
|
11
12
|
context 'with a user' do
|
12
|
-
setup { @user = Factory
|
13
|
+
setup { @user = Factory(:registered_user) }
|
13
14
|
|
14
15
|
context 'A GET to #new' do
|
15
16
|
setup { get :new, :user_id => @user.to_param }
|
@@ -35,10 +36,10 @@ module Clearance
|
|
35
36
|
assert_match /#{@user.email}/, flash[:notice]
|
36
37
|
end
|
37
38
|
|
38
|
-
|
39
|
+
should_redirect_to_url_after_create
|
39
40
|
end
|
40
41
|
|
41
|
-
context 'with a non-
|
42
|
+
context 'with a non-existent email address' do
|
42
43
|
setup do
|
43
44
|
email = 'user1@example.com'
|
44
45
|
assert ! User.exists?(['email = ?', email])
|
@@ -51,8 +52,8 @@ module Clearance
|
|
51
52
|
assert ActionMailer::Base.deliveries.empty?
|
52
53
|
end
|
53
54
|
|
54
|
-
should 'set a :
|
55
|
-
assert_not_nil flash.now[:
|
55
|
+
should 'set a :notice flash' do
|
56
|
+
assert_not_nil flash.now[:notice]
|
56
57
|
end
|
57
58
|
|
58
59
|
should_render_template "new"
|
@@ -64,7 +65,7 @@ module Clearance
|
|
64
65
|
setup do
|
65
66
|
get :edit,
|
66
67
|
:user_id => @user.to_param,
|
67
|
-
:password => @user.
|
68
|
+
:password => @user.encrypted_password,
|
68
69
|
:email => @user.email
|
69
70
|
end
|
70
71
|
|
@@ -77,7 +78,7 @@ module Clearance
|
|
77
78
|
|
78
79
|
should "have a form for the user's email, password, and password confirm" do
|
79
80
|
update_path = ERB::Util.h(user_password_path(@user,
|
80
|
-
:password => @user.
|
81
|
+
:password => @user.encrypted_password,
|
81
82
|
:email => @user.email))
|
82
83
|
|
83
84
|
assert_select 'form[action=?]', update_path do
|
@@ -94,10 +95,7 @@ module Clearance
|
|
94
95
|
end
|
95
96
|
|
96
97
|
should_respond_with :not_found
|
97
|
-
|
98
|
-
should 'render an empty response' do
|
99
|
-
assert @response.body.blank?
|
100
|
-
end
|
98
|
+
should_render_nothing
|
101
99
|
end
|
102
100
|
end
|
103
101
|
|
@@ -108,31 +106,24 @@ module Clearance
|
|
108
106
|
end
|
109
107
|
|
110
108
|
should "not update the user's password" do
|
111
|
-
assert_not_equal @encrypted_new_password, @user.
|
112
|
-
end
|
113
|
-
|
114
|
-
should 'not log the user in' do
|
115
|
-
assert_nil session[:user_id]
|
109
|
+
assert_not_equal @encrypted_new_password, @user.encrypted_password
|
116
110
|
end
|
117
111
|
|
112
|
+
should_not_be_signed_in
|
118
113
|
should_respond_with :not_found
|
119
|
-
|
120
|
-
should 'render an empty response' do
|
121
|
-
assert @response.body.blank?
|
122
|
-
end
|
114
|
+
should_render_nothing
|
123
115
|
end
|
124
116
|
|
125
117
|
context 'with a matching password and password confirmation' do
|
126
118
|
setup do
|
127
119
|
new_password = 'new_password'
|
128
|
-
|
129
|
-
@encrypted_new_password
|
130
|
-
assert_not_equal @encrypted_new_password, @user.crypted_password
|
120
|
+
@encrypted_new_password = @user.encrypt(new_password)
|
121
|
+
assert_not_equal @encrypted_new_password, @user.encrypted_password
|
131
122
|
|
132
123
|
put(:update,
|
133
124
|
:user_id => @user,
|
134
125
|
:email => @user.email,
|
135
|
-
:password => @user.
|
126
|
+
:password => @user.encrypted_password,
|
136
127
|
:user => {
|
137
128
|
:password => new_password,
|
138
129
|
:password_confirmation => new_password
|
@@ -141,25 +132,21 @@ module Clearance
|
|
141
132
|
end
|
142
133
|
|
143
134
|
should "update the user's password" do
|
144
|
-
assert_equal @encrypted_new_password, @user.
|
135
|
+
assert_equal @encrypted_new_password, @user.encrypted_password
|
145
136
|
end
|
146
137
|
|
147
|
-
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
should_redirect_to "user_path(@user)"
|
138
|
+
should_be_signed_in_as { @user }
|
139
|
+
should_redirect_to_url_after_update
|
152
140
|
end
|
153
141
|
|
154
142
|
context 'with password but blank password confirmation' do
|
155
143
|
setup do
|
156
144
|
new_password = 'new_password'
|
157
|
-
|
158
|
-
@encrypted_new_password = Digest::SHA512.hexdigest encryption_format
|
145
|
+
@encrypted_new_password = @user.encrypt(new_password)
|
159
146
|
|
160
147
|
put(:update,
|
161
148
|
:user_id => @user.to_param,
|
162
|
-
:password => @user.
|
149
|
+
:password => @user.encrypted_password,
|
163
150
|
:user => {
|
164
151
|
:password => new_password,
|
165
152
|
:password_confirmation => ''
|
@@ -168,21 +155,16 @@ module Clearance
|
|
168
155
|
end
|
169
156
|
|
170
157
|
should "not update the user's password" do
|
171
|
-
assert_not_equal @encrypted_new_password, @user.
|
172
|
-
end
|
173
|
-
|
174
|
-
should 'not log the user in' do
|
175
|
-
assert_nil session[:user_id]
|
158
|
+
assert_not_equal @encrypted_new_password, @user.encrypted_password
|
176
159
|
end
|
177
160
|
|
161
|
+
should_not_be_signed_in
|
178
162
|
should_respond_with :not_found
|
179
|
-
|
180
|
-
should 'render an empty response' do
|
181
|
-
assert @response.body.blank?
|
182
|
-
end
|
163
|
+
should_render_nothing
|
183
164
|
end
|
184
165
|
end
|
185
166
|
end
|
167
|
+
|
186
168
|
end
|
187
169
|
end
|
188
170
|
|
@@ -3,8 +3,9 @@ module Clearance
|
|
3
3
|
module Functional
|
4
4
|
module SessionsControllerTest
|
5
5
|
|
6
|
-
def self.included(
|
7
|
-
|
6
|
+
def self.included(controller_test)
|
7
|
+
controller_test.class_eval do
|
8
|
+
|
8
9
|
should_filter_params :password
|
9
10
|
|
10
11
|
context "on GET to /sessions/new" do
|
@@ -13,9 +14,10 @@ module Clearance
|
|
13
14
|
should_respond_with :success
|
14
15
|
should_render_template :new
|
15
16
|
should_not_set_the_flash
|
17
|
+
|
16
18
|
should 'display a "sign in" form' do
|
17
19
|
assert_select "form[action=#{session_path}][method=post]",
|
18
|
-
true, "There must be a form to
|
20
|
+
true, "There must be a form to sign in" do
|
19
21
|
assert_select "input[type=text][name=?]",
|
20
22
|
"session[email]", true, "There must be an email field"
|
21
23
|
assert_select "input[type=password][name=?]",
|
@@ -28,10 +30,8 @@ module Clearance
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
context "Given
|
32
|
-
setup
|
33
|
-
@user = Factory(:clearance_user, :confirmed => false)
|
34
|
-
end
|
33
|
+
context "Given a registered user" do
|
34
|
+
setup { @user = Factory(:registered_user) }
|
35
35
|
|
36
36
|
context "a POST to #create with good credentials" do
|
37
37
|
setup do
|
@@ -42,16 +42,11 @@ module Clearance
|
|
42
42
|
end
|
43
43
|
|
44
44
|
should_deny_access(:flash => /confirm/i)
|
45
|
-
|
46
|
-
should "send the confirmation email" do
|
47
|
-
assert_not_nil email = ActionMailer::Base.deliveries[0]
|
48
|
-
assert_match /account confirmation/i, email.subject
|
49
|
-
end
|
50
45
|
end
|
51
46
|
end
|
52
47
|
|
53
|
-
context "Given
|
54
|
-
setup { @user = Factory(:
|
48
|
+
context "Given an email confirmed user" do
|
49
|
+
setup { @user = Factory(:email_confirmed_user) }
|
55
50
|
|
56
51
|
context "a POST to #create with good credentials" do
|
57
52
|
setup do
|
@@ -61,8 +56,8 @@ module Clearance
|
|
61
56
|
end
|
62
57
|
|
63
58
|
should_set_the_flash_to /success/i
|
64
|
-
|
65
|
-
|
59
|
+
should_redirect_to_url_after_create
|
60
|
+
should_be_signed_in_as { @user }
|
66
61
|
end
|
67
62
|
|
68
63
|
context "a POST to #create with bad credentials" do
|
@@ -74,7 +69,7 @@ module Clearance
|
|
74
69
|
|
75
70
|
should_set_the_flash_to /bad/i
|
76
71
|
should_render_template :new
|
77
|
-
|
72
|
+
should_not_be_signed_in
|
78
73
|
end
|
79
74
|
|
80
75
|
context "a POST to #create with good credentials and remember me" do
|
@@ -86,11 +81,11 @@ module Clearance
|
|
86
81
|
end
|
87
82
|
|
88
83
|
should_set_the_flash_to /success/i
|
89
|
-
|
90
|
-
|
84
|
+
should_redirect_to_url_after_create
|
85
|
+
should_be_signed_in_as { @user }
|
91
86
|
|
92
87
|
should 'set the cookie' do
|
93
|
-
assert ! cookies['
|
88
|
+
assert ! cookies['remember_token'].empty?
|
94
89
|
end
|
95
90
|
|
96
91
|
should 'set the remember me token in users table' do
|
@@ -112,7 +107,7 @@ module Clearance
|
|
112
107
|
should_return_from_session :user_id, "nil"
|
113
108
|
|
114
109
|
should 'not create the cookie' do
|
115
|
-
assert_nil cookies['
|
110
|
+
assert_nil cookies['remember_token']
|
116
111
|
end
|
117
112
|
|
118
113
|
should 'not set the remember me token in users table' do
|
@@ -161,26 +156,26 @@ module Clearance
|
|
161
156
|
public_context do
|
162
157
|
context "logging out again" do
|
163
158
|
setup { delete :destroy }
|
164
|
-
|
159
|
+
should_redirect_to_url_after_destroy
|
165
160
|
end
|
166
161
|
end
|
167
162
|
|
168
|
-
|
163
|
+
signed_in_user_context do
|
169
164
|
context "a DELETE to #destroy without a cookie" do
|
170
165
|
setup { delete :destroy }
|
171
166
|
|
172
|
-
should_set_the_flash_to(/
|
173
|
-
|
167
|
+
should_set_the_flash_to(/signed out/i)
|
168
|
+
should_redirect_to_url_after_destroy
|
174
169
|
end
|
175
170
|
|
176
171
|
context 'a DELETE to #destroy with a cookie' do
|
177
172
|
setup do
|
178
|
-
cookies['
|
173
|
+
cookies['remember_token'] = CGI::Cookie.new 'token', 'value'
|
179
174
|
delete :destroy
|
180
175
|
end
|
181
176
|
|
182
177
|
should 'delete the cookie' do
|
183
|
-
assert cookies['
|
178
|
+
assert cookies['remember_token'].empty?
|
184
179
|
end
|
185
180
|
|
186
181
|
should 'delete the remember me token in users table' do
|
@@ -189,6 +184,7 @@ module Clearance
|
|
189
184
|
end
|
190
185
|
end
|
191
186
|
end
|
187
|
+
|
192
188
|
end
|
193
189
|
end
|
194
190
|
|