caleb-restful-authentication 1.1.1

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 (54) hide show
  1. data/CHANGELOG +68 -0
  2. data/README.textile +240 -0
  3. data/Rakefile +32 -0
  4. data/TODO +15 -0
  5. data/generators/authenticated/USAGE +1 -0
  6. data/generators/authenticated/authenticated_generator.rb +508 -0
  7. data/generators/authenticated/lib/insert_routes.rb +54 -0
  8. data/generators/authenticated/templates/_model_partial.html.erb +8 -0
  9. data/generators/authenticated/templates/activation.erb +3 -0
  10. data/generators/authenticated/templates/authenticated_system.rb +189 -0
  11. data/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
  12. data/generators/authenticated/templates/controller.rb +43 -0
  13. data/generators/authenticated/templates/helper.rb +2 -0
  14. data/generators/authenticated/templates/login.html.erb +21 -0
  15. data/generators/authenticated/templates/mailer.rb +33 -0
  16. data/generators/authenticated/templates/migration.rb +29 -0
  17. data/generators/authenticated/templates/model.rb +101 -0
  18. data/generators/authenticated/templates/model_controller.rb +117 -0
  19. data/generators/authenticated/templates/model_helper.rb +93 -0
  20. data/generators/authenticated/templates/model_helper_spec.rb +158 -0
  21. data/generators/authenticated/templates/observer.rb +14 -0
  22. data/generators/authenticated/templates/signup.html.erb +21 -0
  23. data/generators/authenticated/templates/signup_notification.erb +8 -0
  24. data/generators/authenticated/templates/site_keys.rb +38 -0
  25. data/generators/authenticated/templates/spec/controllers/access_control_spec.rb +90 -0
  26. data/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
  27. data/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +139 -0
  28. data/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +200 -0
  29. data/generators/authenticated/templates/spec/fixtures/users.yml +66 -0
  30. data/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
  31. data/generators/authenticated/templates/spec/models/user_spec.rb +295 -0
  32. data/generators/authenticated/templates/stories/rest_auth_stories.rb +22 -0
  33. data/generators/authenticated/templates/stories/rest_auth_stories_helper.rb +81 -0
  34. data/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb +49 -0
  35. data/generators/authenticated/templates/stories/steps/ra_resource_steps.rb +179 -0
  36. data/generators/authenticated/templates/stories/steps/ra_response_steps.rb +171 -0
  37. data/generators/authenticated/templates/stories/steps/user_steps.rb +153 -0
  38. data/generators/authenticated/templates/stories/users/accounts.story +194 -0
  39. data/generators/authenticated/templates/stories/users/sessions.story +134 -0
  40. data/generators/authenticated/templates/test/functional_test.rb +82 -0
  41. data/generators/authenticated/templates/test/mailer_test.rb +31 -0
  42. data/generators/authenticated/templates/test/model_functional_test.rb +95 -0
  43. data/generators/authenticated/templates/test/unit_test.rb +166 -0
  44. data/init.rb +1 -0
  45. data/lib/authentication.rb +40 -0
  46. data/lib/authentication/by_cookie_token.rb +82 -0
  47. data/lib/authentication/by_password.rb +64 -0
  48. data/lib/authorization.rb +14 -0
  49. data/lib/authorization/aasm_roles.rb +64 -0
  50. data/lib/authorization/stateful_roles.rb +63 -0
  51. data/lib/trustification.rb +14 -0
  52. data/lib/trustification/email_validation.rb +20 -0
  53. data/rails/init.rb +6 -0
  54. metadata +115 -0
@@ -0,0 +1,66 @@
1
+ <%
2
+ ## this code must match that in templates/model.rb
3
+ require 'digest/sha1'
4
+ def make_fake_token
5
+ @fake_token_counter ||= 0
6
+ @fake_token_counter += 1
7
+ Digest::SHA1.hexdigest(@fake_token_counter.to_s)
8
+ end
9
+ salts = (1..2).map{ make_fake_token }
10
+ passwds = salts.map{ |salt| password_digest('monkey', salt) }
11
+ -%>
12
+
13
+ quentin:
14
+ id: 1
15
+ <% unless options[:email_as_login] -%>
16
+ login: quentin
17
+ <% end -%>
18
+ email: quentin@example.com
19
+ salt: <%= salts[0] %> # SHA1('0')
20
+ crypted_password: <%= passwds[0] %> # 'monkey'
21
+ created_at: <%%= 5.days.ago.to_s :db %>
22
+ remember_token_expires_at: <%%= 1.days.from_now.to_s %>
23
+ remember_token: <%= make_fake_token %>
24
+ <% if options[:include_activation] -%>
25
+ activation_code:
26
+ activated_at: <%%= 5.days.ago.to_s :db %>
27
+ <% end -%>
28
+ <% if options[:stateful] -%>
29
+ state: active
30
+ <% end -%>
31
+
32
+ aaron:
33
+ id: 2
34
+ <% unless options[:email_as_login] -%>
35
+ login: aaron
36
+ <% end -%>
37
+ email: aaron@example.com
38
+ salt: <%= salts[1] %> # SHA1('1')
39
+ crypted_password: <%= passwds[1] %> # 'monkey'
40
+ created_at: <%%= 1.days.ago.to_s :db %>
41
+ remember_token_expires_at:
42
+ remember_token:
43
+ <% if options[:include_activation] -%>
44
+ activation_code: <%= make_fake_token %>
45
+ activated_at:
46
+ <% end -%>
47
+ <% if options[:stateful] %>
48
+ state: pending
49
+ <% end -%>
50
+
51
+
52
+ old_password_holder:
53
+ id: 3
54
+ <% unless options[:email_as_login] -%>
55
+ login: old_password_holder
56
+ <% end -%>
57
+ email: salty_dog@example.com
58
+ salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
59
+ crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
60
+ created_at: <%%= 1.days.ago.to_s :db %>
61
+ <% if options[:include_activation] %>
62
+ activation_code:
63
+ activated_at: <%%= 5.days.ago.to_s :db %>
64
+ <% end %>
65
+ <% if options[:stateful] %>
66
+ state: active<% end %>
@@ -0,0 +1,141 @@
1
+ require File.dirname(__FILE__) + '<%= ('/..'*model_controller_class_nesting_depth) + '/../spec_helper' %>'
2
+ include ApplicationHelper
3
+ include <%= model_controller_class_name %>Helper
4
+ include AuthenticatedTestHelper
5
+
6
+ describe <%= model_controller_class_name %>Helper do
7
+ before do
8
+ @<%= file_name %> = mock_<%= file_name %>
9
+ end
10
+
11
+ describe "if_authorized" do
12
+ it "yields if authorized" do
13
+ should_receive(:authorized?).with('a','r').and_return(true)
14
+ if_authorized?('a','r'){|action,resource| [action,resource,'hi'] }.should == ['a','r','hi']
15
+ end
16
+ it "does nothing if not authorized" do
17
+ should_receive(:authorized?).with('a','r').and_return(false)
18
+ if_authorized?('a','r'){ 'hi' }.should be_nil
19
+ end
20
+ end
21
+
22
+ describe "link_to_<%= file_name %>" do
23
+ it "should give an error on a nil <%= file_name %>" do
24
+ lambda { link_to_<%= file_name %>(nil) }.should raise_error('Invalid <%= file_name %>')
25
+ end
26
+ it "should link to the given <%= file_name %>" do
27
+ should_receive(:<%= model_controller_routing_name.singularize %>_path).at_least(:once).and_return('/<%= model_controller_file_path %>/1')
28
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[href='/<%= model_controller_file_path %>/1']")
29
+ end
30
+ it "should use given link text if :content_text is specified" do
31
+ link_to_<%= file_name %>(@<%= file_name %>, :content_text => 'Hello there!').should have_tag("a", 'Hello there!')
32
+ end
33
+ it "should use the <%= options[:login_field_name] -%> as link text with no :content_method specified" do
34
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a", 'user_name')
35
+ end
36
+ it "should use the name as link text with :content_method => :name" do
37
+ link_to_<%= file_name %>(@<%= file_name %>, :content_method => :name).should have_tag("a", 'U. Surname')
38
+ end
39
+ it "should use the login as title with no :title_method specified" do
40
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[title='user_name']")
41
+ end
42
+ it "should use the name as link title with :content_method => :name" do
43
+ link_to_<%= file_name %>(@<%= file_name %>, :title_method => :name).should have_tag("a[title='U. Surname']")
44
+ end
45
+ it "should have nickname as a class by default" do
46
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a.nickname")
47
+ end
48
+ it "should take other classes and no longer have the nickname class" do
49
+ result = link_to_<%= file_name %>(@<%= file_name %>, :class => 'foo bar')
50
+ result.should have_tag("a.foo")
51
+ result.should have_tag("a.bar")
52
+ end
53
+ end
54
+
55
+ describe "link_to_login_with_IP" do
56
+ it "should link to the login_path" do
57
+ link_to_login_with_IP().should have_tag("a[href='/login']")
58
+ end
59
+ it "should use given link text if :content_text is specified" do
60
+ link_to_login_with_IP('Hello there!').should have_tag("a", 'Hello there!')
61
+ end
62
+ it "should use the login as link text with no :content_method specified" do
63
+ link_to_login_with_IP().should have_tag("a", '0.0.0.0')
64
+ end
65
+ it "should use the ip address as title" do
66
+ link_to_login_with_IP().should have_tag("a[title='0.0.0.0']")
67
+ end
68
+ it "should by default be like school in summer and have no class" do
69
+ link_to_login_with_IP().should_not have_tag("a.nickname")
70
+ end
71
+ it "should have some class if you tell it to" do
72
+ result = link_to_login_with_IP(nil, :class => 'foo bar')
73
+ result.should have_tag("a.foo")
74
+ result.should have_tag("a.bar")
75
+ end
76
+ it "should have some class if you tell it to" do
77
+ result = link_to_login_with_IP(nil, :tag => 'abbr')
78
+ result.should have_tag("abbr[title='0.0.0.0']")
79
+ end
80
+ end
81
+
82
+ describe "link_to_current_<%= file_name %>, When logged in" do
83
+ before do
84
+ stub!(:current_<%= file_name %>).and_return(@<%= file_name %>)
85
+ end
86
+ it "should link to the given <%= file_name %>" do
87
+ should_receive(:<%= model_controller_routing_name.singularize %>_path).at_least(:once).and_return('/<%= model_controller_file_path %>/1')
88
+ link_to_current_<%= file_name %>().should have_tag("a[href='/<%= model_controller_file_path %>/1']")
89
+ end
90
+ it "should use given link text if :content_text is specified" do
91
+ link_to_current_<%= file_name %>(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
92
+ end
93
+ it "should use the <%= options[:login_field_name] -%> as link text with no :content_method specified" do
94
+ link_to_current_<%= file_name %>().should have_tag("a", 'user_name')
95
+ end
96
+ it "should use the name as link text with :content_method => :name" do
97
+ link_to_current_<%= file_name %>(:content_method => :name).should have_tag("a", 'U. Surname')
98
+ end
99
+ it "should use the <%= options[:login_field_name] -%> as title with no :title_method specified" do
100
+ link_to_current_<%= file_name %>().should have_tag("a[title='user_name']")
101
+ end
102
+ it "should use the name as link title with :content_method => :name" do
103
+ link_to_current_<%= file_name %>(:title_method => :name).should have_tag("a[title='U. Surname']")
104
+ end
105
+ it "should have nickname as a class" do
106
+ link_to_current_<%= file_name %>().should have_tag("a.nickname")
107
+ end
108
+ it "should take other classes and no longer have the nickname class" do
109
+ result = link_to_current_<%= file_name %>(:class => 'foo bar')
110
+ result.should have_tag("a.foo")
111
+ result.should have_tag("a.bar")
112
+ end
113
+ end
114
+
115
+ describe "link_to_current_<%= file_name %>, When logged out" do
116
+ before do
117
+ stub!(:current_<%= file_name %>).and_return(nil)
118
+ end
119
+ it "should link to the login_path" do
120
+ link_to_current_<%= file_name %>().should have_tag("a[href='/login']")
121
+ end
122
+ it "should use given link text if :content_text is specified" do
123
+ link_to_current_<%= file_name %>(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
124
+ end
125
+ it "should use 'not signed in' as link text with no :content_method specified" do
126
+ link_to_current_<%= file_name %>().should have_tag("a", 'not signed in')
127
+ end
128
+ it "should use the ip address as title" do
129
+ link_to_current_<%= file_name %>().should have_tag("a[title='0.0.0.0']")
130
+ end
131
+ it "should by default be like school in summer and have no class" do
132
+ link_to_current_<%= file_name %>().should_not have_tag("a.nickname")
133
+ end
134
+ it "should have some class if you tell it to" do
135
+ result = link_to_current_<%= file_name %>(:class => 'foo bar')
136
+ result.should have_tag("a.foo")
137
+ result.should have_tag("a.bar")
138
+ end
139
+ end
140
+
141
+ end
@@ -0,0 +1,295 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.dirname(__FILE__) + '<%= ('/..'*model_controller_class_nesting_depth) + '/../spec_helper' %>'
3
+
4
+ # Be sure to include AuthenticatedTestHelper in spec/spec_helper.rb instead.
5
+ # Then, you can remove it from this and the functional test.
6
+ include AuthenticatedTestHelper
7
+
8
+ describe <%= class_name %> do
9
+ fixtures :<%= table_name %>
10
+
11
+ describe 'being created' do
12
+ before do
13
+ @<%= file_name %> = nil
14
+ @creating_<%= file_name %> = lambda do
15
+ @<%= file_name %> = create_<%= file_name %>
16
+ violated "#{@<%= file_name %>.errors.full_messages.to_sentence}" if @<%= file_name %>.new_record?
17
+ end
18
+ end
19
+
20
+ it 'increments <%= class_name %>#count' do
21
+ @creating_<%= file_name %>.should change(<%= class_name %>, :count).by(1)
22
+ end
23
+ <% if options[:include_activation] %>
24
+ it 'initializes #activation_code' do
25
+ @creating_<%= file_name %>.call
26
+ @<%= file_name %>.reload
27
+ @<%= file_name %>.activation_code.should_not be_nil
28
+ end
29
+ <% end %><% if options[:stateful] %>
30
+ it 'starts in pending state' do
31
+ @creating_<%= file_name %>.call
32
+ @<%= file_name %>.reload
33
+ @<%= file_name %>.should be_pending
34
+ end
35
+ <% end %> end
36
+
37
+ #
38
+ # Validations
39
+ #
40
+ <% unless options[:email_as_login] %>
41
+ it 'requires login' do
42
+ lambda do
43
+ u = create_<%= file_name %>(:login => nil)
44
+ u.errors.on(:login).should_not be_nil
45
+ end.should_not change(<%= class_name %>, :count)
46
+ end
47
+
48
+ describe 'allows legitimate logins:' do
49
+ ['123', '1234567890_234567890_234567890_234567890',
50
+ 'hello.-_there@funnychar.com'].each do |login_str|
51
+ it "'#{login_str}'" do
52
+ lambda do
53
+ u = create_<%= file_name %>(:login => login_str)
54
+ u.errors.on(:login).should be_nil
55
+ end.should change(<%= class_name %>, :count).by(1)
56
+ end
57
+ end
58
+ end
59
+ describe 'disallows illegitimate logins:' do
60
+ ['12', '1234567890_234567890_234567890_234567890_', "tab\t", "newline\n",
61
+ "Iñtërnâtiônàlizætiøn hasn't happened to ruby 1.8 yet",
62
+ 'semicolon;', 'quote"', 'tick\'', 'backtick`', 'percent%', 'plus+', 'space '].each do |login_str|
63
+ it "'#{login_str}'" do
64
+ lambda do
65
+ u = create_<%= file_name %>(:login => login_str)
66
+ u.errors.on(:login).should_not be_nil
67
+ end.should_not change(<%= class_name %>, :count)
68
+ end
69
+ end
70
+ end
71
+ <% end %>
72
+
73
+ it 'requires password' do
74
+ lambda do
75
+ u = create_<%= file_name %>(:password => nil)
76
+ u.errors.on(:password).should_not be_nil
77
+ end.should_not change(<%= class_name %>, :count)
78
+ end
79
+
80
+ it 'requires password confirmation' do
81
+ lambda do
82
+ u = create_<%= file_name %>(:password_confirmation => nil)
83
+ u.errors.on(:password_confirmation).should_not be_nil
84
+ end.should_not change(<%= class_name %>, :count)
85
+ end
86
+
87
+ it 'requires email' do
88
+ lambda do
89
+ u = create_<%= file_name %>(:email => nil)
90
+ u.errors.on(:email).should_not be_nil
91
+ end.should_not change(<%= class_name %>, :count)
92
+ end
93
+
94
+ describe 'allows legitimate emails:' do
95
+ ['foo@bar.com', 'foo@newskool-tld.museum', 'foo@twoletter-tld.de', 'foo@nonexistant-tld.qq',
96
+ 'r@a.wk', '1234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890@gmail.com',
97
+ 'hello.-_there@funnychar.com', 'uucp%addr@gmail.com', 'hello+routing-str@gmail.com',
98
+ 'domain@can.haz.many.sub.doma.in', 'student.name@university.edu'
99
+ ].each do |email_str|
100
+ it "'#{email_str}'" do
101
+ lambda do
102
+ u = create_<%= file_name %>(:email => email_str)
103
+ u.errors.on(:email).should be_nil
104
+ end.should change(<%= class_name %>, :count).by(1)
105
+ end
106
+ end
107
+ end
108
+ describe 'disallows illegitimate emails' do
109
+ ['!!@nobadchars.com', 'foo@no-rep-dots..com', 'foo@badtld.xxx', 'foo@toolongtld.abcdefg',
110
+ 'Iñtërnâtiônàlizætiøn@hasnt.happened.to.email', 'need.domain.and.tld@de', "tab\t", "newline\n",
111
+ 'r@.wk', '1234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890-234567890@gmail2.com',
112
+ # these are technically allowed but not seen in practice:
113
+ 'uucp!addr@gmail.com', 'semicolon;@gmail.com', 'quote"@gmail.com', 'tick\'@gmail.com', 'backtick`@gmail.com', 'space @gmail.com', 'bracket<@gmail.com', 'bracket>@gmail.com'
114
+ ].each do |email_str|
115
+ it "'#{email_str}'" do
116
+ lambda do
117
+ u = create_<%= file_name %>(:email => email_str)
118
+ u.errors.on(:email).should_not be_nil
119
+ end.should_not change(<%= class_name %>, :count)
120
+ end
121
+ end
122
+ end
123
+
124
+ describe 'allows legitimate names:' do
125
+ ['Andre The Giant (7\'4", 520 lb.) -- has a posse',
126
+ '', '1234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890',
127
+ ].each do |name_str|
128
+ it "'#{name_str}'" do
129
+ lambda do
130
+ u = create_<%= file_name %>(:name => name_str)
131
+ u.errors.on(:name).should be_nil
132
+ end.should change(<%= class_name %>, :count).by(1)
133
+ end
134
+ end
135
+ end
136
+ describe "disallows illegitimate names" do
137
+ ["tab\t", "newline\n",
138
+ '1234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_234567890_',
139
+ ].each do |name_str|
140
+ it "'#{name_str}'" do
141
+ lambda do
142
+ u = create_<%= file_name %>(:name => name_str)
143
+ u.errors.on(:name).should_not be_nil
144
+ end.should_not change(<%= class_name %>, :count)
145
+ end
146
+ end
147
+ end
148
+
149
+ it 'resets password' do
150
+ <%= table_name %>(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
151
+ <%= class_name %>.authenticate('<%= options[:email_as_login] ? "quentin@example.com" : "quentin" %>', 'new password').should == <%= table_name %>(:quentin)
152
+ end
153
+
154
+ it 'does not rehash password' do
155
+ <% if options[:email_as_login] %>
156
+ <%= table_name %>(:quentin).update_attributes(:email => 'quentin2@example.com')
157
+ <% else %>
158
+ <%= table_name %>(:quentin).update_attributes(:login => 'quentin2')
159
+ <% end %>
160
+ <%= class_name %>.authenticate('<%= options[:email_as_login] ? "quentin2@example.com" : "quentin2" %>', 'monkey').should == <%= table_name %>(:quentin)
161
+ end
162
+
163
+ #
164
+ # Authentication
165
+ #
166
+
167
+ it 'authenticates <%= file_name %>' do
168
+ <%= class_name %>.authenticate('<%= options[:email_as_login] ? "quentin@example.com" : "quentin" %>', 'monkey').should == <%= table_name %>(:quentin)
169
+ end
170
+
171
+ it "doesn't authenticate <%= file_name %> with bad password" do
172
+ <%= class_name %>.authenticate('<%= options[:email_as_login] ? "quentin@example.com" : "quentin" %>', 'invalid_password').should be_nil
173
+ end
174
+
175
+ if REST_AUTH_SITE_KEY.blank?
176
+ # old-school passwords
177
+ it "authenticates a user against a hard-coded old-style password" do
178
+ <%= class_name %>.authenticate('old_password_holder', 'test').should == <%= table_name %>(:old_password_holder)
179
+ end
180
+ else
181
+ it "doesn't authenticate a user against a hard-coded old-style password" do
182
+ <%= class_name %>.authenticate('old_password_holder', 'test').should be_nil
183
+ end
184
+
185
+ # New installs should bump this up and set REST_AUTH_DIGEST_STRETCHES to give a 10ms encrypt time or so
186
+ desired_encryption_expensiveness_ms = 0.1
187
+ it "takes longer than #{desired_encryption_expensiveness_ms}ms to encrypt a password" do
188
+ test_reps = 100
189
+ start_time = Time.now; test_reps.times{ <%= class_name %>.authenticate('<%= options[:email_as_login] ? "quentin@example.com" : "quentin" %>', 'monkey'+rand.to_s) }; end_time = Time.now
190
+ auth_time_ms = 1000 * (end_time - start_time)/test_reps
191
+ auth_time_ms.should > desired_encryption_expensiveness_ms
192
+ end
193
+ end
194
+
195
+ #
196
+ # Authentication
197
+ #
198
+
199
+ it 'sets remember token' do
200
+ <%= table_name %>(:quentin).remember_me
201
+ <%= table_name %>(:quentin).remember_token.should_not be_nil
202
+ <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
203
+ end
204
+
205
+ it 'unsets remember token' do
206
+ <%= table_name %>(:quentin).remember_me
207
+ <%= table_name %>(:quentin).remember_token.should_not be_nil
208
+ <%= table_name %>(:quentin).forget_me
209
+ <%= table_name %>(:quentin).remember_token.should be_nil
210
+ end
211
+
212
+ it 'remembers me for one week' do
213
+ before = 1.week.from_now.utc
214
+ <%= table_name %>(:quentin).remember_me_for 1.week
215
+ after = 1.week.from_now.utc
216
+ <%= table_name %>(:quentin).remember_token.should_not be_nil
217
+ <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
218
+ <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after).should be_true
219
+ end
220
+
221
+ it 'remembers me until one week' do
222
+ time = 1.week.from_now.utc
223
+ <%= table_name %>(:quentin).remember_me_until time
224
+ <%= table_name %>(:quentin).remember_token.should_not be_nil
225
+ <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
226
+ <%= table_name %>(:quentin).remember_token_expires_at.should == time
227
+ end
228
+
229
+ it 'remembers me default two weeks' do
230
+ before = 2.weeks.from_now.utc
231
+ <%= table_name %>(:quentin).remember_me
232
+ after = 2.weeks.from_now.utc
233
+ <%= table_name %>(:quentin).remember_token.should_not be_nil
234
+ <%= table_name %>(:quentin).remember_token_expires_at.should_not be_nil
235
+ <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after).should be_true
236
+ end
237
+ <% if options[:stateful] %>
238
+ it 'registers passive <%= file_name %>' do
239
+ <%= file_name %> = create_<%= file_name %>(:password => nil, :password_confirmation => nil)
240
+ <%= file_name %>.should be_passive
241
+ <%= file_name %>.update_attributes(:password => 'new password', :password_confirmation => 'new password')
242
+ <%= file_name %>.register!
243
+ <%= file_name %>.should be_pending
244
+ end
245
+
246
+ it 'suspends <%= file_name %>' do
247
+ <%= table_name %>(:quentin).suspend!
248
+ <%= table_name %>(:quentin).should be_suspended
249
+ end
250
+
251
+ it 'does not authenticate suspended <%= file_name %>' do
252
+ <%= table_name %>(:quentin).suspend!
253
+ <%= class_name %>.authenticate('<%= options[:email_as_login] ? "quentin@example.com" : "quentin" %>', 'monkey').should_not == <%= table_name %>(:quentin)
254
+ end
255
+
256
+ it 'deletes <%= file_name %>' do
257
+ <%= table_name %>(:quentin).deleted_at.should be_nil
258
+ <%= table_name %>(:quentin).delete!
259
+ <%= table_name %>(:quentin).deleted_at.should_not be_nil
260
+ <%= table_name %>(:quentin).should be_deleted
261
+ end
262
+
263
+ describe "being unsuspended" do
264
+ fixtures :<%= table_name %>
265
+
266
+ before do
267
+ @<%= file_name %> = <%= table_name %>(:quentin)
268
+ @<%= file_name %>.suspend!
269
+ end
270
+
271
+ it 'reverts to active state' do
272
+ @<%= file_name %>.unsuspend!
273
+ @<%= file_name %>.should be_active
274
+ end
275
+
276
+ it 'reverts to passive state if activation_code and activated_at are nil' do
277
+ <%= class_name %>.update_all :activation_code => nil, :activated_at => nil
278
+ @<%= file_name %>.reload.unsuspend!
279
+ @<%= file_name %>.should be_passive
280
+ end
281
+
282
+ it 'reverts to pending state if activation_code is set and activated_at is nil' do
283
+ <%= class_name %>.update_all :activation_code => 'foo-bar', :activated_at => nil
284
+ @<%= file_name %>.reload.unsuspend!
285
+ @<%= file_name %>.should be_pending
286
+ end
287
+ end
288
+ <% end %>
289
+ protected
290
+ def create_<%= file_name %>(options = {})
291
+ record = <%= class_name %>.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire69', :password_confirmation => 'quire69' }.merge(options))
292
+ record.<% if options[:stateful] %>register! if record.valid?<% else %>save<% end %>
293
+ record
294
+ end
295
+ end