thoughtbot-clearance 0.3.7 → 0.3.8
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/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
|