thoughtbot-clearance 0.3.7 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +147 -60
- data/Rakefile +29 -21
- data/TODO.textile +1 -15
- data/generators/clearance/clearance_generator.rb +31 -9
- data/generators/clearance/lib/insert_commands.rb +103 -0
- data/generators/clearance/lib/rake_commands.rb +22 -0
- data/generators/clearance/templates/README +37 -0
- data/generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb +3 -1
- data/generators/clearance/templates/app/views/passwords/edit.html.erb +4 -4
- data/generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb +21 -0
- data/generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb +41 -0
- data/generators/clearance/templates/test/{factories.rb → factories/clearance_user.rb} +1 -1
- data/lib/clearance.rb +3 -4
- data/lib/clearance/app/controllers/application_controller.rb +47 -61
- data/lib/clearance/app/controllers/confirmations_controller.rb +25 -33
- data/lib/clearance/app/controllers/passwords_controller.rb +41 -46
- data/lib/clearance/app/controllers/sessions_controller.rb +49 -56
- data/lib/clearance/app/controllers/users_controller.rb +21 -29
- data/lib/clearance/app/models/clearance_mailer.rb +15 -19
- data/lib/clearance/app/models/user.rb +53 -56
- data/lib/clearance/test/functional/confirmations_controller_test.rb +4 -35
- data/lib/clearance/test/functional/passwords_controller_test.rb +9 -5
- data/lib/clearance/test/functional/sessions_controller_test.rb +67 -17
- data/lib/clearance/test/functional/users_controller_test.rb +15 -7
- data/lib/clearance/test/test_helper.rb +10 -81
- data/lib/clearance/test/unit/clearance_mailer_test.rb +5 -5
- data/lib/clearance/test/unit/user_test.rb +42 -59
- data/rails/init.rb +1 -0
- data/shoulda_macros/clearance.rb +45 -0
- metadata +14 -6
- data/generators/clearance/templates/app/views/confirmations/new.html.erb +0 -6
- data/lib/clearance/version.rb +0 -7
@@ -13,24 +13,32 @@ module Clearance
|
|
13
13
|
should_respond_with :success
|
14
14
|
should_render_template :new
|
15
15
|
should_not_set_the_flash
|
16
|
-
|
17
|
-
|
18
|
-
"
|
19
|
-
|
16
|
+
should 'display a "sign in" form' do
|
17
|
+
assert_select "form[action=#{session_path}][method=post]",
|
18
|
+
true, "There must be a form to log in" do
|
19
|
+
assert_select "input[type=text][name=?]",
|
20
|
+
"session[email]", true, "There must be an email field"
|
21
|
+
assert_select "input[type=password][name=?]",
|
22
|
+
"session[password]", true, "There must be a password field"
|
23
|
+
assert_select "input[type=checkbox][name=?]",
|
24
|
+
"session[remember_me]", true, "There must be a 'remember me' check box"
|
25
|
+
assert_select "input[type=submit]", true,
|
26
|
+
"There must be a submit button"
|
27
|
+
end
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
31
|
context "Given an unconfirmed user" do
|
23
32
|
setup do
|
24
|
-
@user = Factory(:
|
33
|
+
@user = Factory(:clearance_user, :confirmed => false)
|
25
34
|
end
|
26
35
|
|
27
36
|
context "a POST to #create with good credentials" do
|
28
37
|
setup do
|
29
38
|
ActionMailer::Base.deliveries.clear
|
30
39
|
post :create, :session => {
|
31
|
-
:email
|
32
|
-
:password => @user.password
|
33
|
-
}
|
40
|
+
:email => @user.email,
|
41
|
+
:password => @user.password }
|
34
42
|
end
|
35
43
|
|
36
44
|
should_deny_access(:flash => /confirm/i)
|
@@ -43,12 +51,13 @@ module Clearance
|
|
43
51
|
end
|
44
52
|
|
45
53
|
context "Given a confirmed user" do
|
46
|
-
setup { @user = Factory(:
|
54
|
+
setup { @user = Factory(:clearance_user, :confirmed => true) }
|
47
55
|
|
48
56
|
context "a POST to #create with good credentials" do
|
49
57
|
setup do
|
50
|
-
post :create, :session => {
|
51
|
-
|
58
|
+
post :create, :session => {
|
59
|
+
:email => @user.email,
|
60
|
+
:password => @user.password }
|
52
61
|
end
|
53
62
|
|
54
63
|
should_set_the_flash_to /success/i
|
@@ -58,8 +67,9 @@ module Clearance
|
|
58
67
|
|
59
68
|
context "a POST to #create with bad credentials" do
|
60
69
|
setup do
|
61
|
-
post :create, :session => {
|
62
|
-
|
70
|
+
post :create, :session => {
|
71
|
+
:email => @user.email,
|
72
|
+
:password => "bad value" }
|
63
73
|
end
|
64
74
|
|
65
75
|
should_set_the_flash_to /bad/i
|
@@ -69,8 +79,10 @@ module Clearance
|
|
69
79
|
|
70
80
|
context "a POST to #create with good credentials and remember me" do
|
71
81
|
setup do
|
72
|
-
post :create, :session => {
|
73
|
-
|
82
|
+
post :create, :session => {
|
83
|
+
:email => @user.email,
|
84
|
+
:password => @user.password,
|
85
|
+
:remember_me => '1' }
|
74
86
|
end
|
75
87
|
|
76
88
|
should_set_the_flash_to /success/i
|
@@ -89,8 +101,10 @@ module Clearance
|
|
89
101
|
|
90
102
|
context "a POST to #create with bad credentials and remember me" do
|
91
103
|
setup do
|
92
|
-
post :create, :session => {
|
93
|
-
|
104
|
+
post :create, :session => {
|
105
|
+
:email => @user.email,
|
106
|
+
:password => "bad value",
|
107
|
+
:remember_me => '1' }
|
94
108
|
end
|
95
109
|
|
96
110
|
should_set_the_flash_to /bad/i
|
@@ -106,6 +120,42 @@ module Clearance
|
|
106
120
|
assert_nil @user.reload.remember_token_expires_at
|
107
121
|
end
|
108
122
|
end
|
123
|
+
|
124
|
+
context "a POST to #create with good credentials and A URL to return back" do
|
125
|
+
context "in the session" do
|
126
|
+
setup do
|
127
|
+
@request.session[:return_to] = '/url_in_the_session'
|
128
|
+
post :create, :session => {
|
129
|
+
:email => @user.email,
|
130
|
+
:password => @user.password }
|
131
|
+
end
|
132
|
+
|
133
|
+
should_redirect_to "'/url_in_the_session'"
|
134
|
+
end
|
135
|
+
|
136
|
+
context "in the request" do
|
137
|
+
setup do
|
138
|
+
post :create, :session => {
|
139
|
+
:email => @user.email,
|
140
|
+
:password => @user.password },
|
141
|
+
:return_to => '/url_in_the_request'
|
142
|
+
end
|
143
|
+
|
144
|
+
should_redirect_to "'/url_in_the_request'"
|
145
|
+
end
|
146
|
+
|
147
|
+
context "in the request and in the session" do
|
148
|
+
setup do
|
149
|
+
@request.session[:return_to] = '/url_in_the_session'
|
150
|
+
post :create, :session => {
|
151
|
+
:email => @user.email,
|
152
|
+
:password => @user.password },
|
153
|
+
:return_to => '/url_in_the_request'
|
154
|
+
end
|
155
|
+
|
156
|
+
should_redirect_to "'/url_in_the_session'"
|
157
|
+
end
|
158
|
+
end
|
109
159
|
end
|
110
160
|
|
111
161
|
public_context do
|
@@ -12,12 +12,20 @@ module Clearance
|
|
12
12
|
should_respond_with :success
|
13
13
|
should_render_template :new
|
14
14
|
should_not_set_the_flash
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
should "display a form to register" do
|
16
|
+
assert_select "form[action=#{users_path}][method=post]",
|
17
|
+
true, "There must be a form to register" do
|
18
|
+
assert_select "input[type=text][name=?]",
|
19
|
+
"user[email]", true, "There must be an email field"
|
20
|
+
assert_select "input[type=password][name=?]",
|
21
|
+
"user[password]", true, "There must be a password field"
|
22
|
+
assert_select "input[type=password][name=?]",
|
23
|
+
"user[password_confirmation]", true, "There must be a password confirmation field"
|
24
|
+
assert_select "input[type=submit]", true,
|
25
|
+
"There must be a submit button"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
21
29
|
context "with params" do
|
22
30
|
setup do
|
23
31
|
@email = 'a@example.com'
|
@@ -33,7 +41,7 @@ module Clearance
|
|
33
41
|
|
34
42
|
context "on POST to /users" do
|
35
43
|
setup do
|
36
|
-
post :create, :user => Factory.build(:
|
44
|
+
post :create, :user => Factory.build(:clearance_user).attributes.merge(
|
37
45
|
{:password => 'skerit',
|
38
46
|
:password_confirmation => 'skerit'})
|
39
47
|
end
|
@@ -2,90 +2,19 @@ module Clearance
|
|
2
2
|
module Test
|
3
3
|
module TestHelper
|
4
4
|
|
5
|
-
def self.included(
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
module InstanceMethods
|
13
|
-
def login_as(user = nil)
|
14
|
-
user ||= Factory(:user)
|
15
|
-
@request.session[:user_id] = user.id
|
16
|
-
return user
|
17
|
-
end
|
18
|
-
|
19
|
-
def logout
|
20
|
-
@request.session[:user_id] = nil
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module ClassMethods
|
25
|
-
def should_deny_access_on(command, opts = {})
|
26
|
-
|
27
|
-
context "on #{command}" do
|
28
|
-
setup { eval command }
|
29
|
-
should_deny_access(opts)
|
5
|
+
def self.included(test_helper)
|
6
|
+
test_helper.class_eval do
|
7
|
+
|
8
|
+
def login_as(user = nil)
|
9
|
+
user ||= Factory(:clearance_user)
|
10
|
+
@request.session[:user_id] = user.id
|
11
|
+
return user
|
30
12
|
end
|
31
|
-
end
|
32
13
|
|
33
|
-
|
34
|
-
|
35
|
-
should_redirect_to opts[:redirect]
|
36
|
-
if opts[:flash]
|
37
|
-
should_set_the_flash_to opts[:flash]
|
38
|
-
else
|
39
|
-
should_not_set_the_flash
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# should_have_form :action => 'admin_users_path',
|
44
|
-
# :method => :get,
|
45
|
-
# :fields => { 'email' => :text }
|
46
|
-
# TODO: http_method should be pulled out
|
47
|
-
def should_have_form(opts)
|
48
|
-
model = self.name.gsub(/ControllerTest$/, '').singularize.downcase
|
49
|
-
model = model[model.rindex('::')+2..model.size] if model.include?('::')
|
50
|
-
http_method, hidden_http_method = form_http_method opts[:method]
|
51
|
-
should "have a #{model} form" do
|
52
|
-
assert_select "form[action=?][method=#{http_method}]", eval(opts[:action]) do
|
53
|
-
if hidden_http_method
|
54
|
-
assert_select "input[type=hidden][name=_method][value=#{hidden_http_method}]"
|
55
|
-
end
|
56
|
-
opts[:fields].each do |attribute, type|
|
57
|
-
attribute = attribute.is_a?(Symbol) ? "#{model}[#{attribute.to_s}]" : attribute
|
58
|
-
assert_select "input[type=#{type.to_s}][name=?]", attribute
|
59
|
-
end
|
60
|
-
assert_select "input[type=submit]"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def form_http_method(http_method)
|
66
|
-
http_method = http_method.nil? ? 'post' : http_method.to_s
|
67
|
-
if http_method == "post" || http_method == "get"
|
68
|
-
return http_method, nil
|
69
|
-
else
|
70
|
-
return "post", http_method
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def logged_in_user_context(&blk)
|
75
|
-
context "A logged in user" do
|
76
|
-
setup do
|
77
|
-
@user = Factory :user
|
78
|
-
login_as @user
|
79
|
-
end
|
80
|
-
merge_block(&blk)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def public_context(&blk)
|
85
|
-
context "The public" do
|
86
|
-
setup { logout }
|
87
|
-
merge_block(&blk)
|
14
|
+
def logout
|
15
|
+
@request.session[:user_id] = nil
|
88
16
|
end
|
17
|
+
|
89
18
|
end
|
90
19
|
end
|
91
20
|
|
@@ -7,7 +7,7 @@ module Clearance
|
|
7
7
|
base.class_eval do
|
8
8
|
context "A change password email" do
|
9
9
|
setup do
|
10
|
-
@user = Factory :
|
10
|
+
@user = Factory :clearance_user
|
11
11
|
@email = ClearanceMailer.create_change_password @user
|
12
12
|
end
|
13
13
|
|
@@ -25,14 +25,14 @@ module Clearance
|
|
25
25
|
assert_equal [@user.email], @email.to
|
26
26
|
end
|
27
27
|
|
28
|
-
should "
|
29
|
-
|
28
|
+
should "set its subject" do
|
29
|
+
assert_match /Change your password/, @email.subject
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
context "A confirmation email" do
|
34
34
|
setup do
|
35
|
-
@user = Factory :
|
35
|
+
@user = Factory :clearance_user
|
36
36
|
@email = ClearanceMailer.create_confirmation @user
|
37
37
|
end
|
38
38
|
|
@@ -41,7 +41,7 @@ module Clearance
|
|
41
41
|
end
|
42
42
|
|
43
43
|
should 'set its subject' do
|
44
|
-
|
44
|
+
assert_match /Account confirmation/, @email.subject
|
45
45
|
end
|
46
46
|
|
47
47
|
should 'set its from address to DO_NOT_REPLY' do
|
@@ -5,24 +5,24 @@ module Clearance
|
|
5
5
|
|
6
6
|
def self.included(base)
|
7
7
|
base.class_eval do
|
8
|
-
should_require_attributes
|
9
|
-
should_allow_values_for
|
8
|
+
should_require_attributes :email, :password
|
9
|
+
should_allow_values_for :email, 'foo@example.com'
|
10
10
|
should_not_allow_values_for :email, 'foo'
|
11
11
|
should_not_allow_values_for :email, 'example.com'
|
12
12
|
|
13
13
|
should "require password validation on create" do
|
14
|
-
user = Factory.build(:
|
14
|
+
user = Factory.build(:clearance_user, :password => 'blah', :password_confirmation => 'boogidy')
|
15
15
|
assert !user.save
|
16
16
|
assert_match(/confirmation/i, user.errors.on(:password))
|
17
17
|
end
|
18
18
|
|
19
19
|
should "create a crypted_password on save" do
|
20
|
-
assert_not_nil Factory(:
|
20
|
+
assert_not_nil Factory(:clearance_user, :crypted_password => nil).crypted_password
|
21
21
|
end
|
22
22
|
|
23
23
|
context 'updating a password' do
|
24
24
|
setup do
|
25
|
-
@user = Factory(:
|
25
|
+
@user = Factory(:clearance_user)
|
26
26
|
assert_not_nil @user.crypted_password
|
27
27
|
@crypt = @user.crypted_password
|
28
28
|
assert_not_nil @user.salt
|
@@ -42,69 +42,52 @@ module Clearance
|
|
42
42
|
setup do
|
43
43
|
@salt = 'salt'
|
44
44
|
User.any_instance.stubs(:initialize_salt)
|
45
|
-
|
45
|
+
|
46
|
+
@user = Factory(:clearance_user, :salt => @salt)
|
46
47
|
@password = @user.password
|
47
48
|
end
|
48
49
|
|
49
50
|
should "require password validation on update" do
|
50
|
-
@user.update_attributes
|
51
|
+
@user.update_attributes :password => "blah",
|
52
|
+
:password_confirmation => "boogidy"
|
51
53
|
assert !@user.save
|
52
54
|
assert_match(/confirmation/i, @user.errors.on(:password))
|
53
55
|
end
|
54
56
|
|
55
57
|
should_require_unique_attributes :email
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@result = User.authenticate @user.email, @password
|
61
|
-
end
|
62
|
-
|
63
|
-
should 'return true' do
|
64
|
-
assert @result
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context 'with bad credentials' do
|
69
|
-
setup do
|
70
|
-
@result = User.authenticate @user.email, 'horribly_wrong_password'
|
71
|
-
end
|
72
|
-
|
73
|
-
should 'return false' do
|
74
|
-
assert !@result
|
75
|
-
end
|
76
|
-
end
|
58
|
+
|
59
|
+
should 'store email in lower case' do
|
60
|
+
@user.update_attributes(:email => 'John.Doe@example.com')
|
61
|
+
assert_equal 'john.doe@example.com', @user.email
|
77
62
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
end
|
63
|
+
|
64
|
+
should "authenticate with good credentials" do
|
65
|
+
assert User.authenticate(@user.email, @password)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "authenticate with good credentials, email in uppercase" do
|
69
|
+
assert User.authenticate(@user.email.upcase, @password)
|
70
|
+
end
|
71
|
+
|
72
|
+
should "not authenticate with bad credentials" do
|
73
|
+
assert ! User.authenticate(@user.email, 'horribly_wrong_password')
|
74
|
+
end
|
75
|
+
|
76
|
+
should "be authenticated with a good password" do
|
77
|
+
assert @user.authenticated?(@password)
|
78
|
+
end
|
79
|
+
|
80
|
+
should "not be authenticated with a bad password" do
|
81
|
+
assert ! @user.authenticated?('horribly_wrong_password')
|
99
82
|
end
|
100
83
|
|
101
84
|
context 'encrypt' do
|
102
85
|
setup do
|
103
86
|
@crypted = @user.encrypt(@password)
|
104
|
-
@expected = Digest::
|
87
|
+
@expected = Digest::SHA512.hexdigest("--#{@salt}--#{@password}--")
|
105
88
|
end
|
106
89
|
|
107
|
-
should 'create a Hash using
|
90
|
+
should 'create a Hash using SHA512 encryption' do
|
108
91
|
assert_equal @expected, @crypted
|
109
92
|
assert_not_equal @password, @crypted
|
110
93
|
end
|
@@ -127,9 +110,7 @@ module Clearance
|
|
127
110
|
end
|
128
111
|
|
129
112
|
context 'forget_me!' do
|
130
|
-
setup
|
131
|
-
@user.forget_me!
|
132
|
-
end
|
113
|
+
setup { @user.forget_me! }
|
133
114
|
|
134
115
|
should 'unset the remember token and expiration date' do
|
135
116
|
assert_nil @user.remember_token
|
@@ -145,7 +126,8 @@ module Clearance
|
|
145
126
|
context 'remember_token?' do
|
146
127
|
context 'when token expires in the future' do
|
147
128
|
setup do
|
148
|
-
@user.update_attribute :remember_token_expires_at,
|
129
|
+
@user.update_attribute :remember_token_expires_at,
|
130
|
+
2.weeks.from_now.utc
|
149
131
|
end
|
150
132
|
|
151
133
|
should 'be true' do
|
@@ -155,7 +137,8 @@ module Clearance
|
|
155
137
|
|
156
138
|
context 'when token expired' do
|
157
139
|
setup do
|
158
|
-
@user.update_attribute :remember_token_expires_at,
|
140
|
+
@user.update_attribute :remember_token_expires_at,
|
141
|
+
2.weeks.ago.utc
|
159
142
|
end
|
160
143
|
|
161
144
|
should 'be false' do
|
@@ -166,7 +149,7 @@ module Clearance
|
|
166
149
|
|
167
150
|
context "User.authenticate with a valid email and password" do
|
168
151
|
setup do
|
169
|
-
@found_user = User.authenticate
|
152
|
+
@found_user = User.authenticate(@user.email, @user.password)
|
170
153
|
end
|
171
154
|
|
172
155
|
should "find that user" do
|
@@ -176,7 +159,7 @@ module Clearance
|
|
176
159
|
|
177
160
|
context "When sent authenticate with an invalid email and password" do
|
178
161
|
setup do
|
179
|
-
@found_user = User.authenticate
|
162
|
+
@found_user = User.authenticate("not", "valid")
|
180
163
|
end
|
181
164
|
|
182
165
|
should "find nothing" do
|
@@ -187,7 +170,7 @@ module Clearance
|
|
187
170
|
|
188
171
|
context "A user" do
|
189
172
|
setup do
|
190
|
-
@user = Factory
|
173
|
+
@user = Factory(:clearance_user)
|
191
174
|
end
|
192
175
|
|
193
176
|
context 'when sent #confirm!' do
|