thoughtbot-clearance 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
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