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 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.1"
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, don't worry: your password hasn't been changed. You can just ignore this email.
7
+ If you didn't request this, ignore this email. Don't worry. Your password hasn't been changed.
@@ -1 +1,2 @@
1
- <%= new_user_confirmation_url :user_id => @user, :salt => @user.salt %>
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 :email
5
- t.string :encrypted_password, :limit => 128
6
- t.string :salt, :limit => 128
7
- t.string :remember_token
8
- t.datetime :remember_token_expires_at
9
- t.boolean :email_confirmed, :default => false, :null => false
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, [:email, :encrypted_password]
13
- add_index :users, [:id, :salt]
12
+ add_index :users, [:id, :token]
14
13
  add_index :users, :email
15
- add_index :users, :remember_token
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 => 180'],
8
- [:salt, 't.string :salt, :limit => 180'],
9
- [:remember_token, 't.string :remember_token'],
10
- [:remember_token_expires_at, 't.datetime :remember_token_expires_at'],
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
- [:index_users_on_email_and_encrypted_password, 'add_index :users, [:email, :encrypted_password]'],
25
- [:index_users_on_id_and_salt, 'add_index :users, [:id, :salt]'],
26
- [:index_users_on_email, 'add_index :users, :email'],
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 :salt
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.find_by_id_and_salt(params[:user_id], params[:salt])
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 = User.find_by_email_and_encrypted_password(params[:email],
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.find_by_email_and_encrypted_password(params[:email],
48
- params[:password])
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.remember_token,
46
- :expires => user.remember_token_expires_at }
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
- hash("--#{salt}--#{string}--")
32
+ generate_hash("--#{salt}--#{string}--")
33
33
  end
34
34
 
35
35
  def remember?
36
- remember_token_expires_at && Time.now.utc < remember_token_expires_at
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.update_attribute :remember_token_expires_at, time
45
- self.update_attribute :remember_token,
46
- encrypt("--#{remember_token_expires_at}--#{password}--")
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
- self.update_attribute :remember_token_expires_at, nil
51
- self.update_attribute :remember_token, nil
50
+ clear_token
51
+ save(false)
52
52
  end
53
53
 
54
54
  def confirm_email!
55
- self.update_attribute :email_confirmed, true
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 hash(string)
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 = hash("--#{Time.now.utc.to_s}--#{password}--")
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 :salt
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 salt" do
14
+ context "on GET to #new with correct id and token" do
15
15
  setup do
16
- get :new, :user_id => @user.to_param, :salt => @user.salt
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 salt" do
25
+ context "on GET to #new with incorrect token" do
26
26
  setup do
27
- salt = ""
28
- assert_not_equal salt, @user.salt
27
+ token = ""
28
+ assert_not_equal token, @user.token
29
29
 
30
- get :new, :user_id => @user.to_param, :salt => salt
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 { @user = Factory(:registered_user) }
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
- should "send the change your password email" do
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
- should "not send a password reminder email" do
53
- assert ActionMailer::Base.deliveries.empty?
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
- context "A GET to #edit" do
65
- context "with an existing user's id and password" do
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
- context "with an existing user's id but not password" do
94
- setup do
95
- get :edit, :user_id => @user.to_param, :password => ""
73
+ should_respond_with :success
74
+ should_render_template "edit"
75
+ should_display_a_password_update_form
96
76
  end
97
77
 
98
- should_respond_with :not_found
99
- should_render_nothing
100
- end
101
- end
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
- should "not update the user's password" do
110
- assert_not_equal @encrypted_new_password, @user.encrypted_password
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 "with a matching password and password confirmation" do
119
- setup do
120
- new_password = "new_password"
121
- @encrypted_new_password = @user.encrypt(new_password)
122
- assert_not_equal @encrypted_new_password, @user.encrypted_password
123
-
124
- put(:update,
125
- :user_id => @user,
126
- :email => @user.email,
127
- :password => @user.encrypted_password,
128
- :user => {
129
- :password => new_password,
130
- :password_confirmation => new_password
131
- })
132
- @user.reload
133
- end
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
- should "update the user's password" do
136
- assert_equal @encrypted_new_password, @user.encrypted_password
137
- end
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
- should_be_signed_in_as { @user }
140
- should_redirect_to_url_after_update
141
- end
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
- context "with password but blank password confirmation" do
144
- setup do
145
- new_password = "new_password"
146
- @encrypted_new_password = @user.encrypt(new_password)
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
- should "not update the user's password" do
159
- assert_not_equal @encrypted_new_password, @user.encrypted_password
160
- end
160
+ should "not update the user's password" do
161
+ assert_not_equal @encrypted_new_password, @user.encrypted_password
162
+ end
161
163
 
162
- should_not_be_signed_in
163
- should_respond_with :not_found
164
- should_render_nothing
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
- end
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
- should 'display a "sign in" form' do
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 { @user = Factory(:email_confirmed_user) }
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 remember me token in users table' do
92
- assert_not_nil @user.reload.remember_token
93
- assert_not_nil @user.reload.remember_token_expires_at
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.remember_token
115
- assert_nil @user.reload.remember_token_expires_at
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
- :return_to => '/url_in_the_request'
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
- :return_to => '/url_in_the_request'
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 'token', 'value'
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.remember_token
183
- assert_nil @user.reload.remember_token_expires_at
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
- should "display a form to register" do
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\?email=#{@user.email.gsub("@", "%40")}&password=#{@user.encrypted_password}}
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\?salt=#{@user.salt}}
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
- :remember_token, :remember_token_expires_at
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 registering with remember_me!" do
113
+ context "When authenticating with remember_me!" do
105
114
  setup do
106
- @user = Factory(:registered_user)
107
- assert_nil @user.remember_token
108
- assert_nil @user.remember_token_expires_at
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
- assert_not_nil @user.remember_token
114
- assert_not_nil @user.remember_token_expires_at
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 :remember_token_expires_at,
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 :remember_token_expires_at,
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.remember_token
136
- assert_nil @user.remember_token_expires_at
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
@@ -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.1
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-26 21:00:00 -08:00
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/lib
77
- - generators/clearance/lib/insert_commands.rb
78
- - generators/clearance/lib/rake_commands.rb
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