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.
- data/README.textile +147 -60
- data/Rakefile +29 -21
- data/TODO.textile +1 -15
- data/generators/clearance/clearance_generator.rb +31 -9
- data/generators/clearance/lib/insert_commands.rb +103 -0
- data/generators/clearance/lib/rake_commands.rb +22 -0
- data/generators/clearance/templates/README +37 -0
- data/generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb +3 -1
- data/generators/clearance/templates/app/views/passwords/edit.html.erb +4 -4
- data/generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb +21 -0
- data/generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb +41 -0
- data/generators/clearance/templates/test/{factories.rb → factories/clearance_user.rb} +1 -1
- data/lib/clearance.rb +3 -4
- data/lib/clearance/app/controllers/application_controller.rb +47 -61
- data/lib/clearance/app/controllers/confirmations_controller.rb +25 -33
- data/lib/clearance/app/controllers/passwords_controller.rb +41 -46
- data/lib/clearance/app/controllers/sessions_controller.rb +49 -56
- data/lib/clearance/app/controllers/users_controller.rb +21 -29
- data/lib/clearance/app/models/clearance_mailer.rb +15 -19
- data/lib/clearance/app/models/user.rb +53 -56
- data/lib/clearance/test/functional/confirmations_controller_test.rb +4 -35
- data/lib/clearance/test/functional/passwords_controller_test.rb +9 -5
- data/lib/clearance/test/functional/sessions_controller_test.rb +67 -17
- data/lib/clearance/test/functional/users_controller_test.rb +15 -7
- data/lib/clearance/test/test_helper.rb +10 -81
- data/lib/clearance/test/unit/clearance_mailer_test.rb +5 -5
- data/lib/clearance/test/unit/user_test.rb +42 -59
- data/rails/init.rb +1 -0
- data/shoulda_macros/clearance.rb +45 -0
- metadata +14 -6
- data/generators/clearance/templates/app/views/confirmations/new.html.erb +0 -6
- 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(
|
7
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
32
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
def forget(user)
|
55
|
+
user.forget_me! if user
|
56
|
+
cookies.delete :auth_token
|
57
|
+
end
|
66
58
|
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
def url_after_create
|
60
|
+
root_url
|
61
|
+
end
|
70
62
|
|
71
|
-
|
72
|
-
|
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(
|
7
|
-
|
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
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
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(
|
7
|
-
|
6
|
+
def self.included(mailer)
|
7
|
+
mailer.class_eval do
|
8
8
|
|
9
|
-
|
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/
|
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(
|
9
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
36
|
+
def encrypt(password)
|
37
|
+
Digest::SHA512.hexdigest "--#{salt}--#{password}--"
|
38
|
+
end
|
47
39
|
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
def remember_token?
|
41
|
+
remember_token_expires_at && Time.now.utc < remember_token_expires_at
|
42
|
+
end
|
51
43
|
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
def remember_me!
|
45
|
+
remember_me_until 2.weeks.from_now.utc
|
46
|
+
end
|
55
47
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
82
|
-
|
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 :
|
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
|
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 :
|
33
|
+
user = Factory :clearance_user
|
65
34
|
salt = ''
|
66
35
|
assert_not_equal salt, user.salt
|
67
36
|
|
68
|
-
|
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 :
|
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
|
66
|
+
:user_id => @user.to_param,
|
63
67
|
:password => @user.crypted_password,
|
64
|
-
: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::
|
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::
|
158
|
+
@encrypted_new_password = Digest::SHA512.hexdigest encryption_format
|
155
159
|
|
156
160
|
put(:update,
|
157
161
|
:user_id => @user.to_param,
|