thoughtbot-clearance 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -29,7 +29,7 @@ Then:
29
29
 
30
30
  h2. Tests
31
31
 
32
- The tests use "Shoulda":http://thoughtbot.com/projects/shoulda and "Factory Girl":http://thoughtbot.com/projects/factory_girl. You should create a User Factory:
32
+ The tests use "Shoulda":http://thoughtbot.com/projects/shoulda >= 2.0.4 and "Factory Girl":http://thoughtbot.com/projects/factory_girl. You should create a User Factory:
33
33
 
34
34
  Factory.sequence :email do |n|
35
35
  "user#{n}@example.com"
@@ -67,6 +67,12 @@ In test/functional/users_controller_test.rb:
67
67
  include Clearance::UsersControllerTest
68
68
  end
69
69
 
70
+ In test/functional/passwords_controller_test.rb:
71
+
72
+ class PasswordsControllerTest < ActionController::TestCase
73
+ include Clearance::PasswordsControllerTest
74
+ end
75
+
70
76
  h2. Schema
71
77
 
72
78
  Change your User model so it has these attributes:
@@ -90,6 +96,23 @@ In app/models/user.rb:
90
96
  include Clearance::Model
91
97
  end
92
98
 
99
+ h2. Mailer
100
+
101
+ In app/models/mailer.rb:
102
+
103
+ class Mailer < ActionMailer::Base
104
+
105
+ default_url_options[:host] = HOST
106
+
107
+ def change_password(user)
108
+ from "donotreply@example.com"
109
+ recipients user.email
110
+ subject "[YOUR APP] Request to change your password"
111
+ body :user => user
112
+ end
113
+
114
+ end
115
+
93
116
  h2. Controllers
94
117
 
95
118
  In app/controllers/application_controller.rb:
@@ -106,11 +129,11 @@ In app/controllers/sessions_controller.rb:
106
129
  include Clearance::SessionsController
107
130
 
108
131
  private
109
-
132
+
110
133
  def url_after_create
111
134
  root_url # the default
112
135
  end
113
-
136
+
114
137
  def url_after_destroy
115
138
  login_url # the default
116
139
  end
@@ -120,18 +143,24 @@ In app/controllers/users_controller.rb:
120
143
 
121
144
  class UsersController < ApplicationController
122
145
  include Clearance::UsersController
123
-
146
+
124
147
  private
125
-
148
+
126
149
  def url_after_create
127
150
  root_url # the default
128
151
  end
129
-
152
+
130
153
  def url_after_update
131
154
  root_url # the default
132
155
  end
133
156
  end
134
157
 
158
+ In app/controllers/passwords_controller.rb:
159
+
160
+ class PasswordsController < ApplicationController
161
+ include Clearance::PasswordsController
162
+ end
163
+
135
164
  h2. Routes
136
165
 
137
166
  map.with_options :controller => 'sessions' do |m|
@@ -139,7 +168,7 @@ h2. Routes
139
168
  m.logout '/logout', :action => 'destroy'
140
169
  end
141
170
  map.resource :session
142
- map.resources :users
171
+ map.resources :users, :has_one => :password
143
172
 
144
173
  h2. Views
145
174
 
data/clearance.gemspec CHANGED
@@ -1,21 +1,23 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "clearance"
3
- s.version = "0.1.6"
4
- s.date = "2008-09-26"
3
+ s.version = "0.1.8"
4
+ s.date = "2008-10-09"
5
5
  s.summary = "Simple, complete Rails authentication."
6
6
  s.email = "dcroak@thoughtbot.com"
7
7
  s.homepage = "http://github.com/thoughtbot/clearance"
8
8
  s.description = "Simple, complete Rails authentication scheme."
9
9
  s.authors = ["thoughtbot, inc.", "Dan Croak", "Josh Nichols", "Mike Breen", "Mike Burns", "Jason Morrison"]
10
- s.files = ["README.textile",
11
- "clearance.gemspec",
12
- "lib/clearance.rb",
13
- "lib/clearance/app/controllers/application_controller.rb",
14
- "lib/clearance/app/models/model.rb",
15
- "lib/clearance/app/controllers/sessions_controller.rb",
16
- "lib/clearance/test/functionals/sessions_controller_test.rb",
17
- "lib/clearance/test/test_helper.rb",
18
- "lib/clearance/test/units/user_test.rb",
19
- "lib/clearance/app/controllers/users_controller.rb",
20
- "lib/clearance/test/functionals/users_controller_test.rb"]
10
+ s.files = ["README.textile",
11
+ "clearance.gemspec",
12
+ "lib/clearance.rb",
13
+ "lib/clearance/app/controllers/application_controller.rb",
14
+ "lib/clearance/app/models/model.rb",
15
+ "lib/clearance/app/controllers/sessions_controller.rb",
16
+ "lib/clearance/test/functionals/sessions_controller_test.rb",
17
+ "lib/clearance/test/test_helper.rb",
18
+ "lib/clearance/test/units/user_test.rb",
19
+ "lib/clearance/app/controllers/users_controller.rb",
20
+ "lib/clearance/test/functionals/users_controller_test.rb",
21
+ "lib/clearance/app/controllers/passwords_controller.rb",
22
+ "lib/clearance/test/functionals/passwords_controller_test.rb"]
21
23
  end
data/lib/clearance.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'clearance/app/controllers/application_controller'
2
2
  require 'clearance/app/controllers/sessions_controller'
3
3
  require 'clearance/app/controllers/users_controller'
4
+ require 'clearance/app/controllers/passwords_controller'
4
5
  require 'clearance/app/models/model'
5
6
  require 'clearance/test/test_helper'
6
7
  require 'clearance/test/functionals/sessions_controller_test'
7
8
  require 'clearance/test/functionals/users_controller_test'
9
+ require 'clearance/test/functionals/passwords_controller_test'
8
10
  require 'clearance/test/units/user_test'
11
+ require 'clearance/test/units/user_mailer_test'
@@ -29,16 +29,16 @@ module Clearance
29
29
  end
30
30
 
31
31
  def user_from_session
32
- User.find_by_id session[:user_id]
32
+ user_model.find_by_id session[:user_id]
33
33
  end
34
34
 
35
35
  def user_from_cookie
36
- user = User.find_by_remember_token(cookies[:auth_token]) if cookies[:auth_token]
36
+ user = user_model.find_by_remember_token(cookies[:auth_token]) if cookies[:auth_token]
37
37
  user && user.remember_token? ? user : nil
38
38
  end
39
39
 
40
40
  def login(user)
41
- create_session_for user
41
+ create_session_for(user)
42
42
  @current_user = user
43
43
  end
44
44
 
@@ -65,6 +65,10 @@ module Clearance
65
65
  flash[:error] = flash_message if flash_message
66
66
  redirect_to opts[:redirect]
67
67
  end
68
+
69
+ def user_model
70
+ User
71
+ end
68
72
  end
69
73
  end
70
74
  end
@@ -0,0 +1,57 @@
1
+ module Clearance
2
+ module PasswordsController
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ before_filter :existing_user?, :only => [:edit, :update]
7
+ filter_parameter_logging :password, :password_confirmation
8
+ include InstanceMethods
9
+ private
10
+ include PrivateInstanceMethods
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+ def new
16
+ end
17
+
18
+ def create
19
+ user = User.find_by_email params[:password][:email]
20
+ if user.nil?
21
+ flash.now[:warning] = 'Unknown email'
22
+ render :action => :new
23
+ else
24
+ UserMailer.deliver_change_password user
25
+ redirect_to login_path
26
+ end
27
+ end
28
+
29
+ def edit
30
+ @user = User.find_by_email_and_crypted_password(params[:email],
31
+ params[:password])
32
+ end
33
+
34
+ def update
35
+ @user = User.find_by_email_and_crypted_password(params[:email],
36
+ params[:password])
37
+ if @user.update_attributes params[:user]
38
+ session[:user_id] = @user.id
39
+ redirect_to @user
40
+ else
41
+ render :action => :edit
42
+ end
43
+ end
44
+ end
45
+
46
+ module PrivateInstanceMethods
47
+ def existing_user?
48
+ user = User.find_by_email_and_crypted_password(params[:email],
49
+ params[:password])
50
+ if user.nil?
51
+ render :nothing => true, :status => :not_found
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -21,7 +21,7 @@ module Clearance
21
21
  end
22
22
 
23
23
  def destroy
24
- forget current_user
24
+ forget(current_user)
25
25
  reset_session
26
26
  flash[:notice] = 'You have been logged out.'
27
27
  redirect_to url_after_destroy
@@ -30,7 +30,7 @@ module Clearance
30
30
 
31
31
  module ProtectedInstanceMethods
32
32
  def login_via_password(email, password, remember_me)
33
- user = User.authenticate(email, password)
33
+ user = user_model.authenticate(email, password)
34
34
  if login(user)
35
35
  create_session_for(user)
36
36
  remember(user) if remember_me == '1'
@@ -16,11 +16,11 @@ module Clearance
16
16
 
17
17
  module InstanceMethods
18
18
  def new
19
- @user = User.new(params[:user])
19
+ @user = user_model.new(params[:user])
20
20
  end
21
21
 
22
22
  def create
23
- @user = User.new params[:user]
23
+ @user = user_model.new params[:user]
24
24
  if @user.save
25
25
  current_user = @user
26
26
  flash[:notice] = "User created and logged in."
@@ -32,6 +32,7 @@ module Clearance
32
32
  end
33
33
 
34
34
  module PrivateInstanceMethods
35
+
35
36
  def url_after_create
36
37
  root_url
37
38
  end
@@ -0,0 +1,188 @@
1
+ module Clearance
2
+ module PasswordsControllerTest
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+
7
+ should_route :get, '/users/1/password/edit', :action => 'edit', :user_id => '1'
8
+
9
+ context 'with a user' do
10
+ setup { @user = Factory :user }
11
+
12
+ context 'A GET to #new' do
13
+ setup { get :new, :user_id => @user_id }
14
+
15
+ should_respond_with :success
16
+ should_render_template 'new'
17
+ end
18
+
19
+ context 'A POST to #create' do
20
+ context "with an existing user's email address" do
21
+ setup do
22
+ ActionMailer::Base.deliveries.clear
23
+
24
+ post :create, :password => { :email => @user.email }
25
+ @email = ActionMailer::Base.deliveries[0]
26
+ end
27
+
28
+ should 'send an email to the user to edit their password' do
29
+ assert @email.subject =~ /request to change your password/i
30
+ end
31
+
32
+ should_redirect_to "new_session_path"
33
+ end
34
+
35
+ context 'with a non-existing email address' do
36
+ setup do
37
+ email = 'user1@example.com'
38
+ assert ! User.exists?(['email = ?', email])
39
+ ActionMailer::Base.deliveries.clear
40
+
41
+ post :create, :password => { :email => email }
42
+ end
43
+
44
+ should 'not send a password reminder email' do
45
+ assert ActionMailer::Base.deliveries.empty?
46
+ end
47
+
48
+ should 'set a :warning flash' do
49
+ assert_not_nil flash.now[:warning]
50
+ end
51
+
52
+ should_render_template "new"
53
+ end
54
+ end
55
+
56
+ context 'A GET to #edit' do
57
+ context "with an existing user's id and password" do
58
+ setup do
59
+ get :edit,
60
+ :user_id => @user.id,
61
+ :password => @user.crypted_password,
62
+ :email => @user.email
63
+ end
64
+
65
+ should 'find the user with the given id and password' do
66
+ assert_equal @user, assigns(:user)
67
+ end
68
+
69
+ should_respond_with :success
70
+ should_render_template "edit"
71
+
72
+ should "have a form for the user's email, password, and password confirm" do
73
+ update_path = ERB::Util.h(user_password_path(@user,
74
+ :password => @user.crypted_password,
75
+ :email => @user.email))
76
+
77
+ assert_select 'form[action=?]', update_path do
78
+ assert_select 'input[name=_method][value=?]', 'put'
79
+ assert_select 'input[name=?]', 'user[password]'
80
+ assert_select 'input[name=?]', 'user[password_confirmation]'
81
+ end
82
+ end
83
+ end
84
+
85
+ context "with an existing user's id but not password" do
86
+ setup do
87
+ get(:edit,
88
+ :user_id => @user.id,
89
+ :password => '')
90
+ end
91
+
92
+ should_respond_with :not_found
93
+
94
+ should 'render an empty response' do
95
+ assert @response.body.blank?
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'A PUT to #update' do
101
+ context "with an existing user's id but not password" do
102
+ setup do
103
+ put(:update,
104
+ :user_id => @user.id,
105
+ :password => '')
106
+ end
107
+
108
+ should "not update the user's password" do
109
+ assert_not_equal @encrypted_new_password, @user.crypted_password
110
+ end
111
+
112
+ should 'not log the user in' do
113
+ assert_nil session[:user_id]
114
+ end
115
+
116
+ should_respond_with :not_found
117
+
118
+ should 'render an empty response' do
119
+ assert @response.body.blank?
120
+ end
121
+ end
122
+
123
+ context 'with a matching password and password confirmation' do
124
+ setup do
125
+ new_password = 'new_password'
126
+ encryption_format = "--#{@user.salt}--#{new_password}--"
127
+ @encrypted_new_password = Digest::SHA1.hexdigest encryption_format
128
+ assert_not_equal @encrypted_new_password, @user.crypted_password
129
+
130
+ put(:update,
131
+ :user_id => @user,
132
+ :email => @user.email,
133
+ :password => @user.crypted_password,
134
+ :user => {
135
+ :password => new_password,
136
+ :password_confirmation => new_password
137
+ })
138
+ @user.reload
139
+ end
140
+
141
+ should "update the user's password" do
142
+ assert_equal @encrypted_new_password, @user.crypted_password
143
+ end
144
+
145
+ should 'log the user in' do
146
+ assert_equal session[:user_id], @user.id
147
+ end
148
+
149
+ should_redirect_to "user_path(@user)"
150
+ end
151
+
152
+ context 'with password but blank password confirmation' do
153
+ setup do
154
+ new_password = 'new_password'
155
+ encryption_format = "--#{@user.salt}--#{new_password}--"
156
+ @encrypted_new_password = Digest::SHA1.hexdigest encryption_format
157
+
158
+ put(:update,
159
+ :user_id => @user.id,
160
+ :password => @user.crypted_password,
161
+ :user => {
162
+ :password => new_password,
163
+ :password_confirmation => ''
164
+ })
165
+ @user.reload
166
+ end
167
+
168
+ should "not update the user's password" do
169
+ assert_not_equal @encrypted_new_password, @user.crypted_password
170
+ end
171
+
172
+ should 'not log the user in' do
173
+ assert_nil session[:user_id]
174
+ end
175
+
176
+ should_respond_with :not_found
177
+
178
+ should 'render an empty response' do
179
+ assert @response.body.blank?
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ end
188
+ end
@@ -6,7 +6,7 @@ module Clearance
6
6
  context "Given a user" do
7
7
  setup { @user = Factory :user }
8
8
 
9
- should_filter :password
9
+ should_filter_params :password
10
10
 
11
11
  context "on GET to /sessions/new" do
12
12
  setup { get :new }
@@ -50,7 +50,7 @@ module Clearance
50
50
 
51
51
  should_deny_access_on "get :new"
52
52
  should_deny_access_on "post :create, :user => {}"
53
- should_filter :password
53
+ should_filter_params :password
54
54
 
55
55
  end
56
56
  end
@@ -35,18 +35,6 @@ module Clearance
35
35
  end
36
36
  end
37
37
 
38
- def should_filter(*keys)
39
- keys.each do |key|
40
- should "filter #{key}" do
41
- assert @controller.respond_to?(:filter_parameters),
42
- "The key #{key} is not filtered"
43
- filtered = @controller.send(:filter_parameters, {key.to_s => key.to_s})
44
- assert_equal '[FILTERED]', filtered[key.to_s],
45
- "The key #{key} is not filtered"
46
- end
47
- end
48
- end
49
-
50
38
  # should_have_form :action => 'admin_users_path',
51
39
  # :method => :get,
52
40
  # :fields => { 'email' => :text }
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.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoughtbot, inc.
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2008-09-26 00:00:00 -07:00
17
+ date: 2008-10-09 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -38,6 +38,8 @@ files:
38
38
  - lib/clearance/test/units/user_test.rb
39
39
  - lib/clearance/app/controllers/users_controller.rb
40
40
  - lib/clearance/test/functionals/users_controller_test.rb
41
+ - lib/clearance/app/controllers/passwords_controller.rb
42
+ - lib/clearance/test/functionals/passwords_controller_test.rb
41
43
  has_rdoc: false
42
44
  homepage: http://github.com/thoughtbot/clearance
43
45
  post_install_message: