thoughtbot-clearance 0.3.7 → 0.3.8

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