vita-clearance 0.6.2

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 (44) hide show
  1. data/CHANGELOG.textile +123 -0
  2. data/LICENSE +21 -0
  3. data/README.textile +109 -0
  4. data/Rakefile +73 -0
  5. data/TODO.textile +6 -0
  6. data/app/controllers/clearance/confirmations_controller.rb +47 -0
  7. data/app/controllers/clearance/passwords_controller.rb +65 -0
  8. data/app/controllers/clearance/sessions_controller.rb +62 -0
  9. data/app/controllers/clearance/users_controller.rb +30 -0
  10. data/app/models/clearance_mailer.rb +19 -0
  11. data/app/views/clearance_mailer/change_password.html.erb +7 -0
  12. data/app/views/clearance_mailer/confirmation.html.erb +2 -0
  13. data/app/views/passwords/edit.html.erb +23 -0
  14. data/app/views/passwords/new.html.erb +15 -0
  15. data/app/views/sessions/new.html.erb +28 -0
  16. data/app/views/users/_form.html.erb +13 -0
  17. data/app/views/users/new.html.erb +6 -0
  18. data/config/clearance_routes.rb +19 -0
  19. data/generators/clearance/USAGE +1 -0
  20. data/generators/clearance/clearance_generator.rb +41 -0
  21. data/generators/clearance/lib/insert_commands.rb +103 -0
  22. data/generators/clearance/lib/rake_commands.rb +22 -0
  23. data/generators/clearance/templates/README +22 -0
  24. data/generators/clearance/templates/factories.rb +13 -0
  25. data/generators/clearance/templates/migrations/create_users.rb +20 -0
  26. data/generators/clearance/templates/migrations/update_users.rb +41 -0
  27. data/generators/clearance/templates/user.rb +3 -0
  28. data/generators/clearance_features/USAGE +1 -0
  29. data/generators/clearance_features/clearance_features_generator.rb +20 -0
  30. data/generators/clearance_features/templates/features/password_reset.feature +31 -0
  31. data/generators/clearance_features/templates/features/sign_in.feature +41 -0
  32. data/generators/clearance_features/templates/features/sign_out.feature +22 -0
  33. data/generators/clearance_features/templates/features/sign_up.feature +30 -0
  34. data/generators/clearance_features/templates/features/step_definitions/clearance_steps.rb +110 -0
  35. data/generators/clearance_features/templates/features/step_definitions/factory_girl_steps.rb +5 -0
  36. data/generators/clearance_features/templates/features/support/paths.rb +22 -0
  37. data/lib/clearance/authentication.rb +80 -0
  38. data/lib/clearance/extensions/errors.rb +4 -0
  39. data/lib/clearance/extensions/rescue.rb +1 -0
  40. data/lib/clearance/user.rb +114 -0
  41. data/lib/clearance.rb +15 -0
  42. data/rails/init.rb +1 -0
  43. data/shoulda_macros/clearance.rb +248 -0
  44. metadata +129 -0
@@ -0,0 +1,114 @@
1
+ require 'digest/sha1'
2
+
3
+ module Clearance
4
+ module User
5
+
6
+ def self.included(model)
7
+ model.extend ClassMethods
8
+ model.send(:include, InstanceMethods)
9
+
10
+ model.class_eval do
11
+ attr_accessible :email, :password, :password_confirmation
12
+ attr_accessor :password, :password_confirmation
13
+
14
+ validates_presence_of :email
15
+ validates_presence_of :password, :if => :password_required?
16
+ validates_confirmation_of :password, :if => :password_required?
17
+ validates_uniqueness_of :email, :case_sensitive => false
18
+ validates_format_of :email, :with => %r{.+@.+\..+}
19
+
20
+ before_save :initialize_salt, :encrypt_password, :initialize_token
21
+ end
22
+ end
23
+
24
+ module InstanceMethods
25
+ def authenticated?(password)
26
+ encrypted_password == encrypt(password)
27
+ end
28
+
29
+ def encrypt(string)
30
+ generate_hash("--#{salt}--#{string}--")
31
+ end
32
+
33
+ def remember?
34
+ token_expires_at && Time.now.utc < token_expires_at
35
+ end
36
+
37
+ def remember_me!
38
+ remember_me_until! 2.weeks.from_now.utc
39
+ end
40
+
41
+ def forget_me!
42
+ clear_token
43
+ save(false)
44
+ end
45
+
46
+ def confirm_email!
47
+ self.email_confirmed = true
48
+ self.token = nil
49
+ save(false)
50
+ end
51
+
52
+ def forgot_password!
53
+ generate_token
54
+ save(false)
55
+ end
56
+
57
+ def update_password(new_password, new_password_confirmation)
58
+ self.password = new_password
59
+ self.password_confirmation = new_password_confirmation
60
+ clear_token if valid?
61
+ save
62
+ end
63
+
64
+ protected
65
+
66
+ def generate_hash(string)
67
+ Digest::SHA1.hexdigest(string)
68
+ end
69
+
70
+ def initialize_salt
71
+ if new_record?
72
+ self.salt = generate_hash("--#{Time.now.utc.to_s}--#{password}--")
73
+ end
74
+ end
75
+
76
+ def encrypt_password
77
+ return if password.blank?
78
+ self.encrypted_password = encrypt(password)
79
+ end
80
+
81
+ def generate_token
82
+ self.token = encrypt("--#{Time.now.utc.to_s}--#{password}--")
83
+ self.token_expires_at = nil
84
+ end
85
+
86
+ def clear_token
87
+ self.token = nil
88
+ self.token_expires_at = nil
89
+ end
90
+
91
+ def initialize_token
92
+ generate_token if new_record?
93
+ end
94
+
95
+ def password_required?
96
+ encrypted_password.blank? || !password.blank?
97
+ end
98
+
99
+ def remember_me_until!(time)
100
+ self.token_expires_at = time
101
+ self.token = encrypt("--#{token_expires_at}--#{password}--")
102
+ save(false)
103
+ end
104
+ end
105
+
106
+ module ClassMethods
107
+ def authenticate(email, password)
108
+ return nil unless user = find_by_email(email)
109
+ return user if user.authenticated?(password)
110
+ end
111
+ end
112
+
113
+ end
114
+ end
data/lib/clearance.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'clearance/extensions/errors'
2
+ require 'clearance/extensions/rescue'
3
+
4
+ require 'clearance/authentication'
5
+ require 'clearance/user'
6
+
7
+ class ActionController::Routing::RouteSet
8
+ def load_routes_with_clearance!
9
+ clearance_routes = File.join(File.dirname(__FILE__), *%w[.. config clearance_routes.rb])
10
+ add_configuration_file(clearance_routes) unless configuration_files.include? clearance_routes
11
+ load_routes_without_clearance!
12
+ end
13
+
14
+ alias_method_chain :load_routes!, :clearance
15
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'clearance'
@@ -0,0 +1,248 @@
1
+ module Clearance
2
+ module Shoulda
3
+
4
+ # STATE OF AUTHENTICATION
5
+
6
+ def should_be_signed_in_as(&block)
7
+ should "be signed in as #{block.bind(self).call}" do
8
+ user = block.bind(self).call
9
+ assert_not_nil user,
10
+ "please pass a User. try: should_be_signed_in_as { @user }"
11
+ assert_equal user.id, session[:user_id],
12
+ "session[:user_id] is not set to User's id"
13
+ end
14
+ end
15
+
16
+ def should_be_signed_in_and_email_confirmed_as(&block)
17
+ should_be_signed_in_as &block
18
+
19
+ should "have confirmed email" do
20
+ user = block.bind(self).call
21
+
22
+ assert_not_nil user
23
+ assert_equal user, assigns(:user)
24
+ assert assigns(:user).email_confirmed?
25
+ end
26
+ end
27
+
28
+ def should_not_be_signed_in
29
+ should "not be signed in" do
30
+ assert_nil session[:user_id]
31
+ end
32
+ end
33
+
34
+ # Examples:
35
+ # should_deny_access_on :get, :index, :flash => /not authorized/i
36
+ # should_deny_access_on :get, :show, :id => '1'
37
+ def should_deny_access_on(http_method, action, opts = {})
38
+ flash_message = opts.delete(:flash)
39
+ context "on #{http_method} to #{action}" do
40
+ setup do
41
+ send(http_method, action, opts)
42
+ end
43
+
44
+ should_deny_access(:flash => flash_message)
45
+ end
46
+ end
47
+
48
+ def should_deny_access(opts = {})
49
+ if opts[:flash]
50
+ should_set_the_flash_to opts[:flash]
51
+ else
52
+ should_not_set_the_flash
53
+ end
54
+
55
+ should_redirect_to('new_session_url') { new_session_url }
56
+ end
57
+
58
+ # HTTP FLUENCY
59
+
60
+ def should_forbid(description, &block)
61
+ should "forbid #{description}" do
62
+ assert_raises ActionController::Forbidden do
63
+ instance_eval(&block)
64
+ end
65
+ end
66
+ end
67
+
68
+ # CONTEXTS
69
+
70
+ def signed_in_user_context(&blk)
71
+ context "A signed in user" do
72
+ setup do
73
+ @user = Factory(:user)
74
+ @user.confirm_email!
75
+ sign_in_as @user
76
+ end
77
+ merge_block(&blk)
78
+ end
79
+ end
80
+
81
+ def public_context(&blk)
82
+ context "The public" do
83
+ setup { sign_out }
84
+ merge_block(&blk)
85
+ end
86
+ end
87
+
88
+ # CREATING USERS
89
+
90
+ def should_create_user_successfully
91
+ should_assign_to :user
92
+ should_change 'User.count', :by => 1
93
+
94
+ should "send the confirmation email" do
95
+ assert_sent_email do |email|
96
+ email.subject =~ /account confirmation/i
97
+ end
98
+ end
99
+
100
+ should_set_the_flash_to /confirm/i
101
+ should_redirect_to_url_after_create
102
+ end
103
+
104
+ # RENDERING
105
+
106
+ def should_render_nothing
107
+ should "render nothing" do
108
+ assert @response.body.blank?
109
+ end
110
+ end
111
+
112
+ # REDIRECTS
113
+
114
+ def should_redirect_to_url_after_create
115
+ should_redirect_to("the post-create url") do
116
+ @controller.send(:url_after_create)
117
+ end
118
+ end
119
+
120
+ def should_redirect_to_url_after_update
121
+ should_redirect_to("the post-update url") do
122
+ @controller.send(:url_after_update)
123
+ end
124
+ end
125
+
126
+ def should_redirect_to_url_after_destroy
127
+ should_redirect_to("the post-destroy url") do
128
+ @controller.send(:url_after_destroy)
129
+ end
130
+ end
131
+
132
+ # VALIDATIONS
133
+
134
+ def should_validate_confirmation_of(attribute, opts = {})
135
+ raise ArgumentError if opts[:factory].nil?
136
+
137
+ context "on save" do
138
+ should_validate_confirmation_is_not_blank opts[:factory], attribute
139
+ should_validate_confirmation_is_not_bad opts[:factory], attribute
140
+ end
141
+ end
142
+
143
+ def should_validate_confirmation_is_not_blank(factory, attribute, opts = {})
144
+ should "validate #{attribute}_confirmation is not blank" do
145
+ model = Factory.build(factory, blank_confirmation_options(attribute))
146
+ model.save
147
+ assert_confirmation_error(model, attribute,
148
+ "#{attribute}_confirmation cannot be blank")
149
+ end
150
+ end
151
+
152
+ def should_validate_confirmation_is_not_bad(factory, attribute, opts = {})
153
+ should "validate #{attribute}_confirmation is different than #{attribute}" do
154
+ model = Factory.build(factory, bad_confirmation_options(attribute))
155
+ model.save
156
+ assert_confirmation_error(model, attribute,
157
+ "#{attribute}_confirmation cannot be different than #{attribute}")
158
+ end
159
+ end
160
+
161
+ # FORMS
162
+
163
+ def should_display_a_password_update_form
164
+ should "have a form for the user's token, password, and password confirm" do
165
+ update_path = ERB::Util.h(
166
+ user_password_path(@user, :token => @user.token)
167
+ )
168
+
169
+ assert_select 'form[action=?]', update_path do
170
+ assert_select 'input[name=_method][value=?]', 'put'
171
+ assert_select 'input[name=?]', 'user[password]'
172
+ assert_select 'input[name=?]', 'user[password_confirmation]'
173
+ end
174
+ end
175
+ end
176
+
177
+ def should_display_a_sign_up_form
178
+ should "display a form to sign up" do
179
+ assert_select "form[action=#{users_path}][method=post]",
180
+ true, "There must be a form to sign up" do
181
+ assert_select "input[type=text][name=?]",
182
+ "user[email]", true, "There must be an email field"
183
+ assert_select "input[type=password][name=?]",
184
+ "user[password]", true, "There must be a password field"
185
+ assert_select "input[type=password][name=?]",
186
+ "user[password_confirmation]", true, "There must be a password confirmation field"
187
+ assert_select "input[type=submit]", true,
188
+ "There must be a submit button"
189
+ end
190
+ end
191
+ end
192
+
193
+ def should_display_a_sign_in_form
194
+ should 'display a "sign in" form' do
195
+ assert_select "form[action=#{session_path}][method=post]",
196
+ true, "There must be a form to sign in" do
197
+ assert_select "input[type=text][name=?]",
198
+ "session[email]", true, "There must be an email field"
199
+ assert_select "input[type=password][name=?]",
200
+ "session[password]", true, "There must be a password field"
201
+ assert_select "input[type=checkbox][name=?]",
202
+ "session[remember_me]", true, "There must be a 'remember me' check box"
203
+ assert_select "input[type=submit]", true,
204
+ "There must be a submit button"
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ module Clearance
212
+ module Shoulda
213
+ module Helpers
214
+ def sign_in_as(user = nil)
215
+ unless user
216
+ user = Factory(:user)
217
+ user.confirm_email!
218
+ end
219
+ @request.session[:user_id] = user.id
220
+ return user
221
+ end
222
+
223
+ def sign_out
224
+ @request.session[:user_id] = nil
225
+ end
226
+
227
+ def blank_confirmation_options(attribute)
228
+ opts = { attribute => attribute.to_s }
229
+ opts.merge("#{attribute}_confirmation".to_sym => "")
230
+ end
231
+
232
+ def bad_confirmation_options(attribute)
233
+ opts = { attribute => attribute.to_s }
234
+ opts.merge("#{attribute}_confirmation".to_sym => "not_#{attribute}")
235
+ end
236
+
237
+ def assert_confirmation_error(model, attribute, message = "confirmation error")
238
+ assert model.errors.on(attribute).include?("doesn't match confirmation"),
239
+ message
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ class Test::Unit::TestCase
246
+ include Clearance::Shoulda::Helpers
247
+ end
248
+ Test::Unit::TestCase.extend(Clearance::Shoulda)
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vita-clearance
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.2
5
+ platform: ruby
6
+ authors:
7
+ - Dan Croak
8
+ - Mike Burns
9
+ - Jason Morrison
10
+ - Joe Ferris
11
+ - Eugene Bolshakov
12
+ - Nick Quaranto
13
+ - Josh Nichols
14
+ - Mike Breen
15
+ - "Marcel G\xC3\xB6rner"
16
+ - Bence Nagy
17
+ - Ben Mabey
18
+ - Eloy Duran
19
+ - Tim Pope
20
+ - Mihai Anca
21
+ - Mark Cornick
22
+ - Shay Arnett
23
+ autorequire:
24
+ bindir: bin
25
+ cert_chain: []
26
+
27
+ date: 2009-04-21 21:00:00 -07:00
28
+ default_executable:
29
+ dependencies: []
30
+
31
+ description: Vita's fork clearance.
32
+ email: support@thoughtbot.com
33
+ executables: []
34
+
35
+ extensions: []
36
+
37
+ extra_rdoc_files: []
38
+
39
+ files:
40
+ - CHANGELOG.textile
41
+ - LICENSE
42
+ - Rakefile
43
+ - README.textile
44
+ - TODO.textile
45
+ - app/controllers
46
+ - app/controllers/clearance
47
+ - app/controllers/clearance/confirmations_controller.rb
48
+ - app/controllers/clearance/passwords_controller.rb
49
+ - app/controllers/clearance/sessions_controller.rb
50
+ - app/controllers/clearance/users_controller.rb
51
+ - app/models
52
+ - app/models/clearance_mailer.rb
53
+ - app/views
54
+ - app/views/clearance_mailer
55
+ - app/views/clearance_mailer/change_password.html.erb
56
+ - app/views/clearance_mailer/confirmation.html.erb
57
+ - app/views/passwords
58
+ - app/views/passwords/edit.html.erb
59
+ - app/views/passwords/new.html.erb
60
+ - app/views/sessions
61
+ - app/views/sessions/new.html.erb
62
+ - app/views/users
63
+ - app/views/users/_form.html.erb
64
+ - app/views/users/new.html.erb
65
+ - config/clearance_routes.rb
66
+ - generators/clearance
67
+ - generators/clearance/clearance_generator.rb
68
+ - generators/clearance/lib
69
+ - generators/clearance/lib/insert_commands.rb
70
+ - generators/clearance/lib/rake_commands.rb
71
+ - generators/clearance/templates
72
+ - generators/clearance/templates/factories.rb
73
+ - generators/clearance/templates/migrations
74
+ - generators/clearance/templates/migrations/create_users.rb
75
+ - generators/clearance/templates/migrations/update_users.rb
76
+ - generators/clearance/templates/README
77
+ - generators/clearance/templates/user.rb
78
+ - generators/clearance/USAGE
79
+ - generators/clearance_features
80
+ - generators/clearance_features/clearance_features_generator.rb
81
+ - generators/clearance_features/templates
82
+ - generators/clearance_features/templates/features
83
+ - generators/clearance_features/templates/features/password_reset.feature
84
+ - generators/clearance_features/templates/features/sign_in.feature
85
+ - generators/clearance_features/templates/features/sign_out.feature
86
+ - generators/clearance_features/templates/features/sign_up.feature
87
+ - generators/clearance_features/templates/features/step_definitions
88
+ - generators/clearance_features/templates/features/step_definitions/clearance_steps.rb
89
+ - generators/clearance_features/templates/features/step_definitions/factory_girl_steps.rb
90
+ - generators/clearance_features/templates/features/support
91
+ - generators/clearance_features/templates/features/support/paths.rb
92
+ - generators/clearance_features/USAGE
93
+ - lib/clearance
94
+ - lib/clearance/authentication.rb
95
+ - lib/clearance/extensions
96
+ - lib/clearance/extensions/errors.rb
97
+ - lib/clearance/extensions/rescue.rb
98
+ - lib/clearance/user.rb
99
+ - lib/clearance.rb
100
+ - shoulda_macros/clearance.rb
101
+ - rails/init.rb
102
+ has_rdoc: false
103
+ homepage: http://github.com/thoughtbot/clearance
104
+ post_install_message:
105
+ rdoc_options: []
106
+
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ version:
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: "0"
120
+ version:
121
+ requirements: []
122
+
123
+ rubyforge_project:
124
+ rubygems_version: 1.2.0
125
+ signing_key:
126
+ specification_version: 2
127
+ summary: Rails authentication with email & password.
128
+ test_files: []
129
+