thoughtbot-clearance 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. data/README.textile +147 -60
  2. data/Rakefile +29 -21
  3. data/TODO.textile +1 -15
  4. data/generators/clearance/clearance_generator.rb +31 -9
  5. data/generators/clearance/lib/insert_commands.rb +103 -0
  6. data/generators/clearance/lib/rake_commands.rb +22 -0
  7. data/generators/clearance/templates/README +37 -0
  8. data/generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb +3 -1
  9. data/generators/clearance/templates/app/views/passwords/edit.html.erb +4 -4
  10. data/generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb +21 -0
  11. data/generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb +41 -0
  12. data/generators/clearance/templates/test/{factories.rb → factories/clearance_user.rb} +1 -1
  13. data/lib/clearance.rb +3 -4
  14. data/lib/clearance/app/controllers/application_controller.rb +47 -61
  15. data/lib/clearance/app/controllers/confirmations_controller.rb +25 -33
  16. data/lib/clearance/app/controllers/passwords_controller.rb +41 -46
  17. data/lib/clearance/app/controllers/sessions_controller.rb +49 -56
  18. data/lib/clearance/app/controllers/users_controller.rb +21 -29
  19. data/lib/clearance/app/models/clearance_mailer.rb +15 -19
  20. data/lib/clearance/app/models/user.rb +53 -56
  21. data/lib/clearance/test/functional/confirmations_controller_test.rb +4 -35
  22. data/lib/clearance/test/functional/passwords_controller_test.rb +9 -5
  23. data/lib/clearance/test/functional/sessions_controller_test.rb +67 -17
  24. data/lib/clearance/test/functional/users_controller_test.rb +15 -7
  25. data/lib/clearance/test/test_helper.rb +10 -81
  26. data/lib/clearance/test/unit/clearance_mailer_test.rb +5 -5
  27. data/lib/clearance/test/unit/user_test.rb +42 -59
  28. data/rails/init.rb +1 -0
  29. data/shoulda_macros/clearance.rb +45 -0
  30. metadata +14 -6
  31. data/generators/clearance/templates/app/views/confirmations/new.html.erb +0 -6
  32. data/lib/clearance/version.rb +0 -7
@@ -3,76 +3,69 @@ module Clearance
3
3
  module Controllers
4
4
  module SessionsController
5
5
 
6
- def self.included(base)
7
- base.class_eval do
6
+ def self.included(controller)
7
+ controller.class_eval do
8
8
  skip_before_filter :authenticate
9
9
  protect_from_forgery :except => :create
10
10
  filter_parameter_logging :password
11
11
 
12
- include InstanceMethods
13
-
14
- private
15
- include PrivateInstanceMethods
16
- end
17
- end
18
-
19
- module InstanceMethods
20
- def create
21
- @user = user_model.authenticate(params[:session][:email], params[:session][:password])
22
- if @user.nil?
23
- login_failure
24
- else
25
- if @user.confirmed?
26
- remember_me = params[:session][:remember_me] if params[:session]
27
- remember(@user) if remember_me == '1'
28
- log_user_in(@user)
29
- login_successful
12
+ def create
13
+ @user = User.authenticate(params[:session][:email], params[:session][:password])
14
+ if @user.nil?
15
+ login_failure
30
16
  else
31
- mailer_model.deliver_confirmation(@user)
32
- deny_access('Account not confirmed. Confirmation email sent.')
17
+ if @user.confirmed?
18
+ remember_me = params[:session][:remember_me] if params[:session]
19
+ remember(@user) if remember_me == '1'
20
+ log_user_in(@user)
21
+ login_successful
22
+ else
23
+ ClearanceMailer.deliver_confirmation(@user)
24
+ deny_access('Account not confirmed. Confirmation email sent.')
25
+ end
33
26
  end
34
27
  end
35
- end
36
28
 
37
- def destroy
38
- forget(current_user)
39
- reset_session
40
- flash[:notice] = 'You have been logged out.'
41
- redirect_to url_after_destroy
42
- end
43
- end
29
+ def destroy
30
+ forget(current_user)
31
+ reset_session
32
+ flash[:notice] = 'You have been logged out.'
33
+ redirect_to url_after_destroy
34
+ end
35
+
36
+ private
37
+
38
+ def login_successful
39
+ flash[:notice] = 'Logged in successfully'
40
+ redirect_back_or url_after_create
41
+ end
44
42
 
45
- module PrivateInstanceMethods
46
- def login_successful
47
- flash[:notice] = 'Logged in successfully'
48
- redirect_back_or url_after_create
49
- end
43
+ def login_failure(message = "Bad email or password.")
44
+ flash.now[:notice] = message
45
+ render :action => :new
46
+ end
50
47
 
51
- def login_failure(message = "Bad email or password.")
52
- flash.now[:notice] = message
53
- render :action => :new
54
- end
55
-
56
- def remember(user)
57
- user.remember_me!
58
- cookies[:auth_token] = { :value => user.remember_token,
59
- :expires => user.remember_token_expires_at }
60
- end
48
+ def remember(user)
49
+ user.remember_me!
50
+ cookies[:auth_token] = { :value => user.remember_token,
51
+ :expires => user.remember_token_expires_at }
52
+ end
61
53
 
62
- def forget(user)
63
- user.forget_me! if user
64
- cookies.delete :auth_token
65
- end
54
+ def forget(user)
55
+ user.forget_me! if user
56
+ cookies.delete :auth_token
57
+ end
66
58
 
67
- def url_after_create
68
- root_url
69
- end
59
+ def url_after_create
60
+ root_url
61
+ end
70
62
 
71
- def url_after_destroy
72
- new_session_url
63
+ def url_after_destroy
64
+ new_session_url
65
+ end
66
+
73
67
  end
74
- end
75
-
68
+ end
76
69
  end
77
70
  end
78
71
  end
@@ -3,42 +3,34 @@ module Clearance
3
3
  module Controllers
4
4
  module UsersController
5
5
 
6
- def self.included(base)
7
- base.class_eval do
6
+ def self.included(controller)
7
+ controller.class_eval do
8
8
  before_filter :redirect_to_root, :only => [:new, :create], :if => :logged_in?
9
9
 
10
10
  filter_parameter_logging :password
11
11
 
12
- include InstanceMethods
13
-
14
- private
15
- include PrivateInstanceMethods
16
- end
17
- end
18
-
19
- module InstanceMethods
20
- def new
21
- @user = user_model.new(params[:user])
22
- end
23
-
24
- def create
25
- @user = user_model.new params[:user]
26
- if @user.save
27
- ClearanceMailer.deliver_confirmation @user
28
- flash[:notice] = "You will receive an email within the next few minutes. It contains instructions for you to confirm your account."
29
- redirect_to url_after_create
30
- else
31
- render :action => "new"
12
+ def new
13
+ @user = User.new(params[:user])
32
14
  end
33
- end
34
- end
35
-
36
- module PrivateInstanceMethods
37
15
 
38
- def url_after_create
39
- new_session_url
40
- end
16
+ def create
17
+ @user = User.new params[:user]
18
+ if @user.save
19
+ ClearanceMailer.deliver_confirmation @user
20
+ flash[:notice] = "You will receive an email within the next few minutes. It contains instructions for you to confirm your account."
21
+ redirect_to url_after_create
22
+ else
23
+ render :action => "new"
24
+ end
25
+ end
41
26
 
27
+ private
28
+
29
+ def url_after_create
30
+ new_session_url
31
+ end
32
+
33
+ end
42
34
  end
43
35
 
44
36
  end
@@ -3,29 +3,25 @@ module Clearance
3
3
  module Models
4
4
  module ClearanceMailer
5
5
 
6
- def self.included(base)
7
- base.class_eval do
6
+ def self.included(mailer)
7
+ mailer.class_eval do
8
8
 
9
- include InstanceMethods
9
+ def change_password(user)
10
+ from DO_NOT_REPLY
11
+ recipients user.email
12
+ subject "Change your password"
13
+ body :user => user
14
+ end
15
+
16
+ def confirmation(user)
17
+ recipients user.email
18
+ from DO_NOT_REPLY
19
+ subject "Account confirmation"
20
+ body :user => user
21
+ end
10
22
 
11
23
  end
12
24
  end
13
-
14
- module InstanceMethods
15
- def change_password(user)
16
- from DO_NOT_REPLY
17
- recipients user.email
18
- subject "[#{PROJECT_NAME.humanize}] Change your password"
19
- body :user => user
20
- end
21
-
22
- def confirmation(user)
23
- recipients user.email
24
- from DO_NOT_REPLY
25
- subject "[#{PROJECT_NAME.humanize}] Account confirmation"
26
- body :user => user
27
- end
28
- end
29
25
 
30
26
  end
31
27
  end
@@ -1,12 +1,12 @@
1
- require 'digest/sha1'
1
+ require 'digest/sha2'
2
2
 
3
3
  module Clearance
4
4
  module App
5
5
  module Models
6
6
  module User
7
7
 
8
- def self.included(base)
9
- base.class_eval do
8
+ def self.included(model)
9
+ model.class_eval do
10
10
 
11
11
  attr_accessible :email, :password, :password_confirmation
12
12
  attr_accessor :password, :password_confirmation
@@ -14,72 +14,69 @@ module Clearance
14
14
  validates_presence_of :email
15
15
  validates_presence_of :password, :if => :password_required?
16
16
  validates_confirmation_of :password, :if => :password_required?
17
- validates_uniqueness_of :email
17
+ validates_uniqueness_of :email, :case_sensitive => false
18
18
  validates_format_of :email, :with => %r{.+@.+\..+}
19
19
 
20
20
  before_save :initialize_salt, :encrypt_password
21
21
 
22
- extend ClassMethods
23
- include InstanceMethods
24
-
25
- protected
22
+ def self.authenticate(email, password)
23
+ user = find(:first, :conditions => ['LOWER(email) = ?', email.to_s.downcase])
24
+ user && user.authenticated?(password) ? user : nil
25
+ end
26
+
27
+ def email=(value)
28
+ value = value.to_s.downcase if value
29
+ write_attribute(:email, value.to_s)
30
+ end
26
31
 
27
- include ProtectedInstanceMethods
28
-
29
- end
30
- end
31
-
32
- module ClassMethods
33
- def authenticate(email, password)
34
- user = find_by_email email
35
- user && user.authenticated?(password) ? user : nil
36
- end
37
- end
38
-
39
- module InstanceMethods
40
- def authenticated?(password)
41
- crypted_password == encrypt(password)
42
- end
32
+ def authenticated?(password)
33
+ crypted_password == encrypt(password)
34
+ end
43
35
 
44
- def encrypt(password)
45
- Digest::SHA1.hexdigest "--#{salt}--#{password}--"
46
- end
36
+ def encrypt(password)
37
+ Digest::SHA512.hexdigest "--#{salt}--#{password}--"
38
+ end
47
39
 
48
- def remember_token?
49
- remember_token_expires_at && Time.now.utc < remember_token_expires_at
50
- end
40
+ def remember_token?
41
+ remember_token_expires_at && Time.now.utc < remember_token_expires_at
42
+ end
51
43
 
52
- def remember_me!
53
- remember_me_until 2.weeks.from_now.utc
54
- end
44
+ def remember_me!
45
+ remember_me_until 2.weeks.from_now.utc
46
+ end
55
47
 
56
- def remember_me_until(time)
57
- self.update_attribute :remember_token_expires_at, time
58
- self.update_attribute :remember_token, encrypt("#{email}--#{remember_token_expires_at}")
59
- end
48
+ def remember_me_until(time)
49
+ self.update_attribute :remember_token_expires_at, time
50
+ self.update_attribute :remember_token,
51
+ encrypt("#{email}--#{remember_token_expires_at}")
52
+ end
60
53
 
61
- def forget_me!
62
- self.update_attribute :remember_token_expires_at, nil
63
- self.update_attribute :remember_token, nil
64
- end
54
+ def forget_me!
55
+ self.update_attribute :remember_token_expires_at, nil
56
+ self.update_attribute :remember_token, nil
57
+ end
58
+
59
+ def confirm!
60
+ self.update_attribute :confirmed, true
61
+ end
65
62
 
66
- def confirm!
67
- self.update_attribute :confirmed, true
68
- end
69
- end
70
-
71
- module ProtectedInstanceMethods
72
- def initialize_salt
73
- self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{email}--") if new_record?
74
- end
63
+ protected
75
64
 
76
- def encrypt_password
77
- return if password.blank?
78
- self.crypted_password = encrypt(password)
79
- end
65
+ def initialize_salt
66
+ if new_record?
67
+ self.salt = Digest::SHA512.hexdigest("--#{Time.now.to_s}--#{email}--")
68
+ end
69
+ end
80
70
 
81
- def password_required?
82
- crypted_password.blank? || !password.blank?
71
+ def encrypt_password
72
+ return if password.blank?
73
+ self.crypted_password = encrypt(password)
74
+ end
75
+
76
+ def password_required?
77
+ crypted_password.blank? || !password.blank?
78
+ end
79
+
83
80
  end
84
81
  end
85
82
 
@@ -9,7 +9,7 @@ module Clearance
9
9
  context 'A GET to #new' do
10
10
  context "with the User with the given id's salt" do
11
11
  setup do
12
- @user = Factory :user
12
+ @user = Factory :clearance_user
13
13
  get :new, :user_id => @user.to_param, :salt => @user.salt
14
14
  end
15
15
 
@@ -17,39 +17,8 @@ module Clearance
17
17
  assert_equal @user, assigns(:user)
18
18
  end
19
19
 
20
- should_respond_with :success
21
- should_render_template :new
22
- end
23
-
24
- context "without the User with the given id's salt" do
25
- setup do
26
- user = Factory :user
27
- salt = ''
28
- assert_not_equal salt, user.salt
29
-
30
- get :new, :user_id => user.to_param, :salt => ''
31
- end
32
-
33
- should_respond_with :not_found
34
-
35
- should 'render nothing' do
36
- assert @response.body.blank?
37
- end
38
- end
39
- end
40
-
41
- context 'A POST to #create' do
42
- context "with the User with the given id's salt" do
43
- setup do
44
- @user = Factory :user
45
- assert ! @user.confirmed?
46
-
47
- post :create, :user_id => @user, :salt => @user.salt
48
- @user.reload
49
- end
50
-
51
20
  should 'confirm the User record with the given id' do
52
- assert @user.confirmed?
21
+ assert assigns(:user).confirmed?
53
22
  end
54
23
 
55
24
  should 'log the User in' do
@@ -61,11 +30,11 @@ module Clearance
61
30
 
62
31
  context "without the User with the given id's salt" do
63
32
  setup do
64
- user = Factory :user
33
+ user = Factory :clearance_user
65
34
  salt = ''
66
35
  assert_not_equal salt, user.salt
67
36
 
68
- post :create, :user_id => user.id, :salt => salt
37
+ get :new, :user_id => user.to_param, :salt => ''
69
38
  end
70
39
 
71
40
  should_respond_with :not_found
@@ -9,7 +9,7 @@ module Clearance
9
9
  should_route :get, '/users/1/password/edit', :action => 'edit', :user_id => '1'
10
10
 
11
11
  context 'with a user' do
12
- setup { @user = Factory :user }
12
+ setup { @user = Factory :clearance_user }
13
13
 
14
14
  context 'A GET to #new' do
15
15
  setup { get :new, :user_id => @user.to_param }
@@ -30,6 +30,10 @@ module Clearance
30
30
  should 'send an email to the user to edit their password' do
31
31
  assert @email.subject =~ /change your password/i
32
32
  end
33
+
34
+ should 'set a :notice flash with the user email address' do
35
+ assert_match /#{@user.email}/, flash[:notice]
36
+ end
33
37
 
34
38
  should_redirect_to "@controller.send(:url_after_create)"
35
39
  end
@@ -59,9 +63,9 @@ module Clearance
59
63
  context "with an existing user's id and password" do
60
64
  setup do
61
65
  get :edit,
62
- :user_id => @user.to_param,
66
+ :user_id => @user.to_param,
63
67
  :password => @user.crypted_password,
64
- :email => @user.email
68
+ :email => @user.email
65
69
  end
66
70
 
67
71
  should 'find the user with the given id and password' do
@@ -122,7 +126,7 @@ module Clearance
122
126
  setup do
123
127
  new_password = 'new_password'
124
128
  encryption_format = "--#{@user.salt}--#{new_password}--"
125
- @encrypted_new_password = Digest::SHA1.hexdigest encryption_format
129
+ @encrypted_new_password = Digest::SHA512.hexdigest encryption_format
126
130
  assert_not_equal @encrypted_new_password, @user.crypted_password
127
131
 
128
132
  put(:update,
@@ -151,7 +155,7 @@ module Clearance
151
155
  setup do
152
156
  new_password = 'new_password'
153
157
  encryption_format = "--#{@user.salt}--#{new_password}--"
154
- @encrypted_new_password = Digest::SHA1.hexdigest encryption_format
158
+ @encrypted_new_password = Digest::SHA512.hexdigest encryption_format
155
159
 
156
160
  put(:update,
157
161
  :user_id => @user.to_param,