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.
- 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,
|