clearance 0.10.3.2 → 0.10.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of clearance might be problematic. Click here for more details.
- data/.rspec +2 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -5
- data/Gemfile.lock +2 -11
- data/README.md +5 -8
- data/Rakefile +5 -7
- data/VERSION +1 -1
- data/app/views/passwords/new.html.erb +1 -1
- data/app/views/sessions/new.html.erb +1 -1
- data/app/views/users/_form.html.erb +1 -1
- data/features/engine/visitor_resets_password.feature +11 -0
- data/features/engine/visitor_signs_in.feature +10 -0
- data/features/engine/visitor_signs_up.feature +6 -4
- data/features/integration.feature +1 -1
- data/features/step_definitions/engine/clearance_steps.rb +8 -0
- data/lib/clearance/shoulda_macros.rb +5 -3
- data/lib/clearance/user.rb +12 -4
- data/lib/generators/clearance/install/install_generator.rb +2 -2
- data/spec/controllers/passwords_controller_spec.rb +177 -0
- data/spec/controllers/sessions_controller_spec.rb +160 -0
- data/spec/controllers/users_controller_spec.rb +64 -0
- data/{test → spec}/factories.rb +0 -0
- data/spec/models/clearance_mailer_spec.rb +27 -0
- data/spec/models/user_spec.rb +260 -0
- data/spec/spec_helper.rb +65 -0
- data/spec/support/authorization.rb +18 -0
- data/spec/support/clearance_redirects.rb +21 -0
- data/spec/support/cookies.rb +72 -0
- metadata +16 -27
- data/test/controllers/passwords_controller_test.rb +0 -198
- data/test/controllers/sessions_controller_test.rb +0 -150
- data/test/controllers/users_controller_test.rb +0 -64
- data/test/models/clearance_mailer_test.rb +0 -29
- data/test/models/user_test.rb +0 -244
- data/test/test_helper.rb +0 -59
data/.rspec
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
0.10.4
|
2
|
+
------------------
|
3
|
+
|
4
|
+
* Formtastic views generator removed.
|
5
|
+
* Emails forced to be downcased (particularly for iPhone user case). (Adam Conrad)
|
6
|
+
* Suite converted from test/unit to RSpec. (Joe Ferris)
|
7
|
+
* Password reset requires a password. (Joel Meador)
|
8
|
+
* Use HTML5 email fields.
|
9
|
+
|
1
10
|
0.10.3.2
|
2
11
|
------------------
|
3
12
|
|
data/Gemfile
CHANGED
@@ -5,17 +5,13 @@ gem "rake"
|
|
5
5
|
gem "rails", ">= 3.0.3"
|
6
6
|
gem "thin"
|
7
7
|
gem "shoulda"
|
8
|
-
gem "sqlite3
|
8
|
+
gem "sqlite3"
|
9
9
|
gem "factory_girl"
|
10
10
|
gem "diesel"
|
11
11
|
gem "cucumber-rails"
|
12
12
|
gem "capybara"
|
13
13
|
gem "factory_girl_rails"
|
14
14
|
gem "rspec-rails"
|
15
|
-
gem "formtastic"
|
16
|
-
gem "database_cleaner"
|
17
15
|
gem "dynamic_form"
|
18
16
|
gem "launchy"
|
19
|
-
gem "redgreen"
|
20
17
|
gem "mocha"
|
21
|
-
|
data/Gemfile.lock
CHANGED
@@ -57,7 +57,6 @@ GEM
|
|
57
57
|
cucumber (>= 0.8.0)
|
58
58
|
culerity (0.2.14)
|
59
59
|
daemons (1.1.0)
|
60
|
-
database_cleaner (0.6.0)
|
61
60
|
diesel (0.1.4)
|
62
61
|
railties (~> 3.0.3)
|
63
62
|
diff-lcs (1.1.2)
|
@@ -71,10 +70,6 @@ GEM
|
|
71
70
|
railties (>= 3.0.0)
|
72
71
|
ffi (0.6.3)
|
73
72
|
rake (>= 0.8.7)
|
74
|
-
formtastic (1.2.3)
|
75
|
-
actionpack (>= 2.3.7)
|
76
|
-
activesupport (>= 2.3.7)
|
77
|
-
i18n (~> 0.4)
|
78
73
|
gherkin (2.3.3)
|
79
74
|
json (~> 1.4.6)
|
80
75
|
i18n (0.5.0)
|
@@ -112,7 +107,6 @@ GEM
|
|
112
107
|
rake (>= 0.8.7)
|
113
108
|
thor (~> 0.14.4)
|
114
109
|
rake (0.8.7)
|
115
|
-
redgreen (1.2.2)
|
116
110
|
rspec (2.3.0)
|
117
111
|
rspec-core (~> 2.3.0)
|
118
112
|
rspec-expectations (~> 2.3.0)
|
@@ -133,7 +127,7 @@ GEM
|
|
133
127
|
json_pure
|
134
128
|
rubyzip
|
135
129
|
shoulda (2.11.3)
|
136
|
-
sqlite3
|
130
|
+
sqlite3 (1.3.3)
|
137
131
|
term-ansicolor (1.0.5)
|
138
132
|
thin (1.2.7)
|
139
133
|
daemons (>= 1.0.9)
|
@@ -154,18 +148,15 @@ DEPENDENCIES
|
|
154
148
|
capybara
|
155
149
|
cucumber
|
156
150
|
cucumber-rails
|
157
|
-
database_cleaner
|
158
151
|
diesel
|
159
152
|
dynamic_form
|
160
153
|
factory_girl
|
161
154
|
factory_girl_rails
|
162
|
-
formtastic
|
163
155
|
launchy
|
164
156
|
mocha
|
165
157
|
rails (>= 3.0.3)
|
166
158
|
rake
|
167
|
-
redgreen
|
168
159
|
rspec-rails
|
169
160
|
shoulda
|
170
|
-
sqlite3
|
161
|
+
sqlite3
|
171
162
|
thin
|
data/README.md
CHANGED
@@ -73,13 +73,17 @@ See config/routes.rb for all the routes Clearance provides.
|
|
73
73
|
Actions that redirect (create, update, and destroy) in Clearance controllers
|
74
74
|
can be overridden by re-defining url_after_(action) methods as seen above.
|
75
75
|
|
76
|
+
Clearance is an engine, so it provides views for you. If you want to customize those views, there is a handy shortcut to copy the views into your app:
|
77
|
+
|
78
|
+
rails generate clearance:views
|
79
|
+
|
76
80
|
Optional Cucumber features
|
77
81
|
--------------------------
|
78
82
|
|
79
83
|
As your app evolves, you want to know that authentication still works. If you
|
80
84
|
use [Cucumber](http://cukes.info), run the Clearance features generator:
|
81
85
|
|
82
|
-
rails generate
|
86
|
+
rails generate clearance:features
|
83
87
|
|
84
88
|
Edit your Gemfile to include:
|
85
89
|
|
@@ -93,13 +97,6 @@ Then run your tests!
|
|
93
97
|
|
94
98
|
rake
|
95
99
|
|
96
|
-
Optional Formtastic views
|
97
|
-
-------------------------
|
98
|
-
|
99
|
-
Clearance can also generate [Formtastic](http://github.com/justinfrench/formtastic) views:
|
100
|
-
|
101
|
-
rails generate clearance_views
|
102
|
-
|
103
100
|
Extensions
|
104
101
|
----------
|
105
102
|
|
data/Rakefile
CHANGED
@@ -6,12 +6,10 @@ require 'rake'
|
|
6
6
|
require 'rake/gempackagetask'
|
7
7
|
require 'cucumber/rake/task'
|
8
8
|
require 'diesel/tasks'
|
9
|
+
require 'rspec/core/rake_task'
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
task.libs << "test"
|
13
|
-
task.pattern = "test/*/*_test.rb"
|
14
|
-
task.verbose = false
|
11
|
+
RSpec::Core::RakeTask.new do |t|
|
12
|
+
t.pattern = 'spec/**/*_spec.rb'
|
15
13
|
end
|
16
14
|
|
17
15
|
Cucumber::Rake::Task.new(:cucumber) do |t|
|
@@ -19,6 +17,6 @@ Cucumber::Rake::Task.new(:cucumber) do |t|
|
|
19
17
|
t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')]
|
20
18
|
end
|
21
19
|
|
22
|
-
desc "Default: run the
|
23
|
-
task :default => [:
|
20
|
+
desc "Default: run the specs and cucumber features"
|
21
|
+
task :default => [:spec, :cucumber]
|
24
22
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.4
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<%= form_for :password, :url => passwords_path do |form| %>
|
8
8
|
<div class="text_field">
|
9
9
|
<%= form.label :email, "Email address" %>
|
10
|
-
<%= form.text_field :email %>
|
10
|
+
<%= form.text_field :email, :type => "email" %>
|
11
11
|
</div>
|
12
12
|
<div class="submit_field">
|
13
13
|
<%= form.submit "Reset password" %>
|
@@ -15,6 +15,17 @@ Feature: Password reset
|
|
15
15
|
Then I should see "instructions for changing your password"
|
16
16
|
And a password reset message should be sent to "email@example.com"
|
17
17
|
|
18
|
+
Scenario: User is signed up updated his password and tries blank password and confirmation
|
19
|
+
Given I signed up with "email@example.com/password"
|
20
|
+
And I go to the password reset request page
|
21
|
+
Then I should see an email field
|
22
|
+
And I fill in "Email address" with "email@example.com"
|
23
|
+
And I press "Reset password"
|
24
|
+
When I follow the password reset link sent to "email@example.com"
|
25
|
+
And I update my password with "/"
|
26
|
+
Then I should see an error message
|
27
|
+
And I should be signed out
|
28
|
+
|
18
29
|
Scenario: User is signed up updated his password and types wrong confirmation
|
19
30
|
Given I signed up with "email@example.com/password"
|
20
31
|
And I go to the password reset request page
|
@@ -21,8 +21,18 @@ Feature: Sign in
|
|
21
21
|
Scenario: Visitor signs in successfully
|
22
22
|
Given I am signed up as "email@person.com/password"
|
23
23
|
When I go to the sign in page
|
24
|
+
Then I should see an email field
|
24
25
|
And I sign in as "email@person.com/password"
|
25
26
|
Then I should see "Signed in"
|
26
27
|
And I should be signed in
|
27
28
|
When I return next time
|
28
29
|
Then I should be signed in
|
30
|
+
|
31
|
+
Scenario: Visitor signs in successfully with uppercase email
|
32
|
+
Given I am signed up as "email@person.com/password"
|
33
|
+
When I go to the sign in page
|
34
|
+
And I sign in as "Email@person.com/password"
|
35
|
+
Then I should see "Signed in"
|
36
|
+
And I should be signed in
|
37
|
+
When I return next time
|
38
|
+
Then I should be signed in
|
@@ -4,17 +4,19 @@ Feature: Sign up
|
|
4
4
|
As a visitor
|
5
5
|
I want to sign up
|
6
6
|
|
7
|
-
|
7
|
+
Background:
|
8
8
|
When I go to the sign up page
|
9
|
-
|
9
|
+
Then I should see an email field
|
10
|
+
|
11
|
+
Scenario: Visitor signs up with invalid data
|
12
|
+
When I fill in "Email" with "invalidemail"
|
10
13
|
And I fill in "Password" with "password"
|
11
14
|
And I fill in "Confirm password" with ""
|
12
15
|
And I press "Sign up"
|
13
16
|
Then I should see error messages
|
14
17
|
|
15
18
|
Scenario: Visitor signs up with valid data
|
16
|
-
When I
|
17
|
-
And I fill in "Email" with "email@person.com"
|
19
|
+
When I fill in "Email" with "email@person.com"
|
18
20
|
And I fill in "Password" with "password"
|
19
21
|
And I fill in "Confirm password" with "password"
|
20
22
|
And I press "Sign up"
|
@@ -11,9 +11,9 @@ Feature: integrate with application
|
|
11
11
|
And I add the "cucumber-rails" gem
|
12
12
|
And I add the "capybara" gem
|
13
13
|
And I add the "rspec-rails" gem
|
14
|
-
And I add the "formtastic" gem
|
15
14
|
And I add the "factory_girl_rails" gem
|
16
15
|
And I add the "dynamic_form" gem
|
16
|
+
And I add the "database_cleaner" gem
|
17
17
|
And I add the "clearance" gem from this project
|
18
18
|
And I add the "diesel" gem
|
19
19
|
And I run "bundle install --local"
|
@@ -8,6 +8,14 @@ Then /^I should see an error message$/ do
|
|
8
8
|
Then %{I should see "error prohibited"}
|
9
9
|
end
|
10
10
|
|
11
|
+
Then /^I should see an email field$/ do
|
12
|
+
if page.respond_to?(:should)
|
13
|
+
page.should have_css("input[type='email']")
|
14
|
+
else
|
15
|
+
assert page.has_css("input[type='email']")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
11
19
|
# Database
|
12
20
|
|
13
21
|
Given /^no user exists with an email of "(.*)"$/ do |email|
|
@@ -65,7 +65,9 @@ module Clearance
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
if defined?(Test::Unit::TestCase)
|
69
|
+
class Test::Unit::TestCase
|
70
|
+
include Clearance::Shoulda::Helpers
|
71
|
+
end
|
72
|
+
Test::Unit::TestCase.extend(Clearance::Shoulda)
|
70
73
|
end
|
71
|
-
Test::Unit::TestCase.extend(Clearance::Shoulda)
|
data/lib/clearance/user.rb
CHANGED
@@ -35,6 +35,8 @@ module Clearance
|
|
35
35
|
def self.included(model)
|
36
36
|
model.class_eval do
|
37
37
|
attr_accessor :password, :password_confirmation
|
38
|
+
private
|
39
|
+
attr_accessor :password_changing
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
@@ -64,6 +66,7 @@ module Clearance
|
|
64
66
|
# salt, token, password encryption are handled before_save.
|
65
67
|
def self.included(model)
|
66
68
|
model.class_eval do
|
69
|
+
before_validation :downcase_email
|
67
70
|
before_save :initialize_salt,
|
68
71
|
:encrypt_password
|
69
72
|
before_create :generate_remember_token
|
@@ -115,6 +118,7 @@ module Clearance
|
|
115
118
|
# @example
|
116
119
|
# user.update_password('new-password', 'new-password')
|
117
120
|
def update_password(new_password, new_password_confirmation)
|
121
|
+
self.password_changing = true
|
118
122
|
self.password = new_password
|
119
123
|
self.password_confirmation = new_password_confirmation
|
120
124
|
if valid?
|
@@ -162,17 +166,21 @@ module Clearance
|
|
162
166
|
end
|
163
167
|
|
164
168
|
# True if the password has been set and the password is not being
|
165
|
-
# updated
|
166
|
-
# facebook, etc).
|
169
|
+
# updated and we are not updating the password. Override to allow
|
170
|
+
# other forms of authentication (username, facebook, etc).
|
167
171
|
# @return [Boolean] true if the password field can be left blank for this user
|
168
172
|
def password_optional?
|
169
|
-
encrypted_password.present? && password.blank?
|
173
|
+
encrypted_password.present? && password.blank? && password_changing.blank?
|
170
174
|
end
|
171
175
|
|
172
176
|
def password_required?
|
173
177
|
# warn "[DEPRECATION] password_required?: use !password_optional? instead"
|
174
178
|
!password_optional?
|
175
179
|
end
|
180
|
+
|
181
|
+
def downcase_email
|
182
|
+
self.email = email.to_s.downcase
|
183
|
+
end
|
176
184
|
end
|
177
185
|
|
178
186
|
module ClassMethods
|
@@ -183,7 +191,7 @@ module Clearance
|
|
183
191
|
# @example
|
184
192
|
# User.authenticate("email@example.com", "password")
|
185
193
|
def authenticate(email, password)
|
186
|
-
return nil unless user = find_by_email(email)
|
194
|
+
return nil unless user = find_by_email(email.to_s.downcase)
|
187
195
|
return user if user.authenticated?(password)
|
188
196
|
end
|
189
197
|
end
|
@@ -20,9 +20,9 @@ module Clearance
|
|
20
20
|
end
|
21
21
|
|
22
22
|
if File.exists?("spec")
|
23
|
-
template "
|
23
|
+
template "spec/factories.rb", "spec/factories/clearance.rb"
|
24
24
|
else
|
25
|
-
template "
|
25
|
+
template "spec/factories.rb", "test/factories/clearance.rb"
|
26
26
|
end
|
27
27
|
|
28
28
|
readme "README"
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Clearance::PasswordsController do
|
4
|
+
|
5
|
+
include Shoulda::ActionMailer::Matchers
|
6
|
+
|
7
|
+
it { should route(:get, '/users/1/password/edit').
|
8
|
+
to(:controller => 'clearance/passwords', :action => 'edit', :user_id => '1') }
|
9
|
+
|
10
|
+
describe "a signed up user" do
|
11
|
+
before do
|
12
|
+
@user = Factory(:user)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "on GET to #new" do
|
16
|
+
before { get :new, :user_id => @user.to_param }
|
17
|
+
|
18
|
+
it { should respond_with(:success) }
|
19
|
+
it { should render_template(:new) }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "on POST to #create" do
|
23
|
+
describe "with correct email address" do
|
24
|
+
before do
|
25
|
+
ActionMailer::Base.deliveries.clear
|
26
|
+
post :create, :password => { :email => @user.email }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should generate a token for the change your password email" do
|
30
|
+
@user.reload.confirmation_token.should_not be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it { should have_sent_email.with_subject(/change your password/i) }
|
34
|
+
|
35
|
+
it { should set_the_flash.to(/password/i) }
|
36
|
+
it { should redirect_to_url_after_create }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "with incorrect email address" do
|
40
|
+
before do
|
41
|
+
email = "user1@example.com"
|
42
|
+
(::User.exists?(['email = ?', email])).should_not be
|
43
|
+
ActionMailer::Base.deliveries.clear
|
44
|
+
@user.reload.confirmation_token.should == @user.confirmation_token
|
45
|
+
|
46
|
+
post :create, :password => { :email => email }
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not generate a token for the change your password email" do
|
50
|
+
@user.reload.confirmation_token.should == @user.confirmation_token
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not send a password reminder email" do
|
54
|
+
ActionMailer::Base.deliveries.should be_empty
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should set the failure flash to Unknown email" do
|
58
|
+
flash.now[:failure].should =~ /unknown email/i
|
59
|
+
end
|
60
|
+
|
61
|
+
it { should render_template(:new) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "a signed up user and forgotten password" do
|
67
|
+
before do
|
68
|
+
@user = Factory(:user)
|
69
|
+
@user.forgot_password!
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "on GET to #edit with correct id and token" do
|
73
|
+
before do
|
74
|
+
get :edit, :user_id => @user.to_param,
|
75
|
+
:token => @user.confirmation_token
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should find the user" do
|
79
|
+
assigns(:user).should == @user
|
80
|
+
end
|
81
|
+
|
82
|
+
it { should respond_with(:success) }
|
83
|
+
it { should render_template(:edit) }
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "on GET to #edit with correct id but blank token" do
|
87
|
+
before do
|
88
|
+
get :edit, :user_id => @user.to_param, :token => ""
|
89
|
+
end
|
90
|
+
|
91
|
+
it { should set_the_flash.to(/double check the URL/i) }
|
92
|
+
it { should render_template(:new) }
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "on GET to #edit with correct id but no token" do
|
96
|
+
before do
|
97
|
+
get :edit, :user_id => @user.to_param
|
98
|
+
end
|
99
|
+
|
100
|
+
it { should set_the_flash.to(/double check the URL/i) }
|
101
|
+
it { should render_template(:new) }
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "on PUT to #update with matching password and password confirmation" do
|
105
|
+
before do
|
106
|
+
new_password = "new_password"
|
107
|
+
@encrypted_new_password = @user.send(:encrypt, new_password)
|
108
|
+
@user.encrypted_password.should_not == @encrypted_new_password
|
109
|
+
|
110
|
+
put(:update,
|
111
|
+
:user_id => @user,
|
112
|
+
:token => @user.confirmation_token,
|
113
|
+
:user => {
|
114
|
+
:password => new_password,
|
115
|
+
:password_confirmation => new_password
|
116
|
+
})
|
117
|
+
@user.reload
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should update password" do
|
121
|
+
@user.encrypted_password.should == @encrypted_new_password
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should clear confirmation token" do
|
125
|
+
@user.confirmation_token.should be_nil
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should set remember token" do
|
129
|
+
@user.remember_token.should_not be_nil
|
130
|
+
end
|
131
|
+
|
132
|
+
it { should set_the_flash.to(/signed in/i) }
|
133
|
+
it { should redirect_to_url_after_update }
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "on PUT to #update with password but blank password confirmation" do
|
137
|
+
before do
|
138
|
+
new_password = "new_password"
|
139
|
+
@encrypted_new_password = @user.send(:encrypt, new_password)
|
140
|
+
|
141
|
+
put(:update,
|
142
|
+
:user_id => @user.to_param,
|
143
|
+
:token => @user.confirmation_token,
|
144
|
+
:user => {
|
145
|
+
:password => new_password,
|
146
|
+
:password_confirmation => ''
|
147
|
+
})
|
148
|
+
@user.reload
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should not update password" do
|
152
|
+
@user.encrypted_password.should_not == @encrypted_new_password
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should not clear token" do
|
156
|
+
@user.confirmation_token.should_not be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not be signed in" do
|
160
|
+
cookies[:remember_token].should be_nil
|
161
|
+
end
|
162
|
+
|
163
|
+
it { should_not set_the_flash }
|
164
|
+
it { should respond_with(:success) }
|
165
|
+
it { should render_template(:edit) }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "given two users and user one signs in" do
|
170
|
+
before do
|
171
|
+
@user_one = Factory(:user)
|
172
|
+
@user_two = Factory(:user)
|
173
|
+
sign_in_as @user_one
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|