devise_token_auth_multi_email 0.9.3 → 0.9.5

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/Rakefile +4 -8
  4. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +2 -9
  5. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +35 -5
  6. data/app/controllers/devise_token_auth/registrations_controller.rb +24 -18
  7. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +6 -3
  8. data/lib/devise_token_auth/engine.rb +40 -1
  9. data/lib/devise_token_auth/version.rb +1 -1
  10. data/lib/devise_token_auth_multi_email.rb +3 -0
  11. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +4 -4
  12. data/test/controllers/devise_token_auth/multi_email_coexistence_test.rb +130 -0
  13. data/test/controllers/devise_token_auth/multi_email_confirmations_controller_test.rb +210 -0
  14. data/test/controllers/devise_token_auth/multi_email_passwords_controller_test.rb +247 -0
  15. data/test/controllers/devise_token_auth/multi_email_registrations_controller_test.rb +137 -0
  16. data/test/controllers/devise_token_auth/multi_email_sessions_controller_test.rb +191 -0
  17. data/test/controllers/devise_token_auth/multi_email_token_validations_controller_test.rb +140 -0
  18. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +5 -4
  19. data/test/controllers/devise_token_auth/standard_user_registrations_controller_test.rb +165 -0
  20. data/test/coverage/assets/0.13.2/colorbox/loading.gif +0 -0
  21. data/test/coverage/assets/0.13.2/loading.gif +0 -0
  22. data/test/dummy/app/active_record/multi_email_user.rb +45 -0
  23. data/test/dummy/app/active_record/multi_email_user_email.rb +21 -0
  24. data/test/dummy/config/application.rb +6 -1
  25. data/test/dummy/config/initializers/omniauth.rb +15 -1
  26. data/test/dummy/config/routes.rb +8 -0
  27. data/test/dummy/db/migrate/20260401000001_devise_token_auth_create_multi_email_users.rb +49 -0
  28. data/test/dummy/db/migrate/20260401000002_devise_token_auth_create_multi_email_user_emails.rb +29 -0
  29. data/test/dummy/db/schema.rb +81 -41
  30. data/test/dummy/db/test.sqlite3-shm +0 -0
  31. data/test/dummy/tmp/generators/app/controllers/application_controller.rb +6 -0
  32. data/test/dummy/tmp/generators/app/models/{user.rb → azpire/v1/human_resource/user.rb} +1 -1
  33. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +11 -5
  34. data/test/dummy/tmp/generators/db/migrate/{20210305040222_devise_token_auth_create_users.rb → 20260408021432_devise_token_auth_create_azpire_v1_human_resource_users.rb} +7 -7
  35. data/test/factories/users.rb +1 -0
  36. data/test/lib/devise_token_auth/controllers/helpers_test.rb +402 -0
  37. data/test/lib/devise_token_auth/token_factory_test.rb +18 -18
  38. data/test/lib/generators/devise_token_auth/install_generator_test.rb +60 -0
  39. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +1 -1
  40. data/test/lib/generators/devise_token_auth/install_mongoid_generator_test.rb +218 -0
  41. data/test/models/multi_email_user_email_test.rb +95 -0
  42. data/test/models/multi_email_user_test.rb +225 -0
  43. data/test/test_helper.rb +21 -11
  44. data/test/validators/devise_token_auth_email_validator_test.rb +114 -0
  45. metadata +59 -27
  46. data/test/dummy/tmp/generators/app/models/mang.rb +0 -9
  47. data/test/dummy/tmp/generators/config/routes.rb +0 -9
  48. data/test/dummy/tmp/generators/db/migrate/20210305040222_devise_token_auth_create_mangs.rb +0 -49
@@ -0,0 +1,402 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ # Tests for DeviseTokenAuth::Controllers::Helpers
6
+ #
7
+ # The Helpers module:
8
+ # - Defines instance methods per mapping via .define_helpers (authenticate_X!,
9
+ # X_signed_in?, current_X, X_session, render_authenticate_error)
10
+ # - Defines group methods via .devise_token_auth_group (authenticate_G!,
11
+ # G_signed_in?, current_G, current_Gs, set_group_user_by_token,
12
+ # render_authenticate_error)
13
+ # - Overrides ClassMethods#log_process_action to default status to 401
14
+
15
+ class DeviseTokenAuth::Controllers::HelpersTest < ActionDispatch::IntegrationTest
16
+ include Warden::Test::Helpers
17
+
18
+ # ------------------------------------------------------------------
19
+ # describe_helpers: methods generated by define_helpers
20
+ # These are exercised via /demo/members_only (DemoUserController, :user
21
+ # mapping) and /demo/members_only_mang (DemoMangController, :mang mapping).
22
+ # ------------------------------------------------------------------
23
+ describe 'define_helpers – generated instance methods' do
24
+ describe 'authenticate_user!' do
25
+ describe 'when user is not authenticated' do
26
+ before do
27
+ get '/demo/members_only', params: {}, headers: {}
28
+ end
29
+
30
+ it 'returns 401' do
31
+ assert_equal 401, response.status
32
+ end
33
+
34
+ it 'returns an unauthenticated error JSON body' do
35
+ body = JSON.parse(response.body)
36
+ assert_includes body['errors'], I18n.t('devise.failure.unauthenticated')
37
+ end
38
+
39
+ it 'does not return auth headers' do
40
+ refute response.headers['access-token']
41
+ end
42
+ end
43
+
44
+ describe 'when user is authenticated' do
45
+ before do
46
+ @resource = create(:user, :confirmed)
47
+ @auth_headers = @resource.create_new_auth_token
48
+ age_token(@resource, @auth_headers['client'])
49
+
50
+ get '/demo/members_only', params: {}, headers: @auth_headers
51
+ end
52
+
53
+ it 'returns 200' do
54
+ assert_equal 200, response.status
55
+ end
56
+
57
+ it 'returns a new access token' do
58
+ assert response.headers['access-token'].present?
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'user_signed_in?' do
64
+ describe 'when user is authenticated' do
65
+ before do
66
+ @resource = create(:user, :confirmed)
67
+ @auth_headers = @resource.create_new_auth_token
68
+ age_token(@resource, @auth_headers['client'])
69
+
70
+ get '/demo/members_only', params: {}, headers: @auth_headers
71
+ end
72
+
73
+ it 'returns true' do
74
+ assert @controller.user_signed_in?
75
+ end
76
+ end
77
+
78
+ describe 'when user is not authenticated' do
79
+ before do
80
+ get '/demo/members_only', params: {}, headers: {}
81
+ end
82
+
83
+ it 'returns false' do
84
+ refute @controller.user_signed_in?
85
+ end
86
+ end
87
+ end
88
+
89
+ describe 'current_user' do
90
+ before do
91
+ @resource = create(:user, :confirmed)
92
+ @auth_headers = @resource.create_new_auth_token
93
+ age_token(@resource, @auth_headers['client'])
94
+
95
+ get '/demo/members_only', params: {}, headers: @auth_headers
96
+ end
97
+
98
+ it 'returns the authenticated user' do
99
+ assert_equal @resource, @controller.current_user
100
+ end
101
+
102
+ it 'memoizes the result (same object on repeated calls)' do
103
+ first = @controller.current_user
104
+ second = @controller.current_user
105
+ assert_same first, second
106
+ end
107
+ end
108
+
109
+ describe 'user_session' do
110
+ describe 'when user is authenticated' do
111
+ before do
112
+ @resource = create(:user, :confirmed)
113
+ @auth_headers = @resource.create_new_auth_token
114
+ age_token(@resource, @auth_headers['client'])
115
+
116
+ get '/demo/members_only', params: {}, headers: @auth_headers
117
+ end
118
+
119
+ it 'returns a non-nil session object' do
120
+ assert_not_nil @controller.user_session
121
+ end
122
+ end
123
+
124
+ describe 'when user is not authenticated' do
125
+ before do
126
+ get '/demo/members_only', params: {}, headers: {}
127
+ end
128
+
129
+ it 'returns nil' do
130
+ assert_nil @controller.user_session
131
+ end
132
+ end
133
+ end
134
+
135
+ describe 'mang_signed_in? and current_mang – different mapping' do
136
+ describe 'when mang is authenticated' do
137
+ before do
138
+ @mang = create(:mang_user, :confirmed)
139
+ @auth_headers = @mang.create_new_auth_token
140
+ age_token(@mang, @auth_headers['client'])
141
+
142
+ get '/demo/members_only_mang', params: {}, headers: @auth_headers
143
+ end
144
+
145
+ it 'returns 200' do
146
+ assert_equal 200, response.status
147
+ end
148
+
149
+ it 'mang_signed_in? returns true' do
150
+ assert @controller.mang_signed_in?
151
+ end
152
+
153
+ it 'current_mang returns the authenticated mang' do
154
+ assert_equal @mang, @controller.current_mang
155
+ end
156
+
157
+ it 'user_signed_in? returns false (different mapping)' do
158
+ refute @controller.user_signed_in?
159
+ end
160
+ end
161
+ end
162
+
163
+ describe 'render_authenticate_error' do
164
+ before do
165
+ get '/demo/members_only', params: {}, headers: {}
166
+ end
167
+
168
+ it 'returns a JSON body with an errors key' do
169
+ body = JSON.parse(response.body)
170
+ assert body.key?('errors'), 'response body should have an "errors" key'
171
+ end
172
+
173
+ it 'errors array contains the unauthenticated message' do
174
+ body = JSON.parse(response.body)
175
+ assert_includes body['errors'], I18n.t('devise.failure.unauthenticated')
176
+ end
177
+
178
+ it 'sets Content-Type to application/json' do
179
+ assert_match %r{application/json}, response.content_type
180
+ end
181
+ end
182
+ end
183
+
184
+ # ------------------------------------------------------------------
185
+ # devise_token_auth_group – methods generated for a group mapping
186
+ # Exercised via /demo/members_only_group (DemoGroupController, :member
187
+ # group containing :user and :mang).
188
+ # ------------------------------------------------------------------
189
+ describe 'devise_token_auth_group – generated group methods' do
190
+ describe 'authenticate_member!' do
191
+ describe 'when no group member is authenticated' do
192
+ before do
193
+ get '/demo/members_only_group', params: {}, headers: {}
194
+ end
195
+
196
+ it 'returns 401' do
197
+ assert_equal 401, response.status
198
+ end
199
+
200
+ it 'returns an unauthenticated error JSON body' do
201
+ body = JSON.parse(response.body)
202
+ assert_includes body['errors'], I18n.t('devise.failure.unauthenticated')
203
+ end
204
+ end
205
+
206
+ describe 'when a user (first mapping) is authenticated' do
207
+ before do
208
+ @resource = create(:user, :confirmed)
209
+ @auth_headers = @resource.create_new_auth_token
210
+ age_token(@resource, @auth_headers['client'])
211
+
212
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
213
+ end
214
+
215
+ it 'returns 200' do
216
+ assert_equal 200, response.status
217
+ end
218
+ end
219
+
220
+ describe 'when a mang (second mapping) is authenticated' do
221
+ before do
222
+ @mang = create(:mang_user, :confirmed)
223
+ @auth_headers = @mang.create_new_auth_token
224
+ age_token(@mang, @auth_headers['client'])
225
+
226
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
227
+ end
228
+
229
+ it 'returns 200' do
230
+ assert_equal 200, response.status
231
+ end
232
+ end
233
+ end
234
+
235
+ describe 'member_signed_in?' do
236
+ describe 'when user is authenticated' do
237
+ before do
238
+ @resource = create(:user, :confirmed)
239
+ @auth_headers = @resource.create_new_auth_token
240
+ age_token(@resource, @auth_headers['client'])
241
+
242
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
243
+ end
244
+
245
+ it 'returns true' do
246
+ assert @controller.member_signed_in?
247
+ end
248
+ end
249
+
250
+ describe 'when mang is authenticated' do
251
+ before do
252
+ @mang = create(:mang_user, :confirmed)
253
+ @auth_headers = @mang.create_new_auth_token
254
+ age_token(@mang, @auth_headers['client'])
255
+
256
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
257
+ end
258
+
259
+ it 'returns true' do
260
+ assert @controller.member_signed_in?
261
+ end
262
+ end
263
+
264
+ describe 'when no one is authenticated' do
265
+ before do
266
+ get '/demo/members_only_group', params: {}, headers: {}
267
+ end
268
+
269
+ it 'returns false' do
270
+ refute @controller.member_signed_in?
271
+ end
272
+ end
273
+ end
274
+
275
+ describe 'current_member' do
276
+ describe 'when user is authenticated' do
277
+ before do
278
+ @resource = create(:user, :confirmed)
279
+ @auth_headers = @resource.create_new_auth_token
280
+ age_token(@resource, @auth_headers['client'])
281
+
282
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
283
+ end
284
+
285
+ it 'returns the authenticated user as current member' do
286
+ assert_equal @resource, @controller.current_member
287
+ end
288
+
289
+ it 'memoizes the result' do
290
+ first = @controller.current_member
291
+ second = @controller.current_member
292
+ assert_same first, second
293
+ end
294
+ end
295
+
296
+ describe 'when mang is authenticated' do
297
+ before do
298
+ @mang = create(:mang_user, :confirmed)
299
+ @auth_headers = @mang.create_new_auth_token
300
+ age_token(@mang, @auth_headers['client'])
301
+
302
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
303
+ end
304
+
305
+ it 'returns the authenticated mang as current member' do
306
+ assert_equal @mang, @controller.current_member
307
+ end
308
+ end
309
+ end
310
+
311
+ describe 'current_members' do
312
+ describe 'when user is authenticated' do
313
+ before do
314
+ @resource = create(:user, :confirmed)
315
+ @auth_headers = @resource.create_new_auth_token
316
+ age_token(@resource, @auth_headers['client'])
317
+
318
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
319
+ end
320
+
321
+ it 'includes the authenticated user' do
322
+ assert_includes @controller.current_members, @resource
323
+ end
324
+
325
+ it 'does not include unauthenticated users' do
326
+ other = create(:user, :confirmed)
327
+ refute_includes @controller.current_members, other
328
+ end
329
+ end
330
+
331
+ describe 'when mang is authenticated' do
332
+ before do
333
+ @mang = create(:mang_user, :confirmed)
334
+ @auth_headers = @mang.create_new_auth_token
335
+ age_token(@mang, @auth_headers['client'])
336
+
337
+ get '/demo/members_only_group', params: {}, headers: @auth_headers
338
+ end
339
+
340
+ it 'includes the authenticated mang' do
341
+ assert_includes @controller.current_members, @mang
342
+ end
343
+ end
344
+
345
+ describe 'when no one is authenticated' do
346
+ before do
347
+ get '/demo/members_only_group', params: {}, headers: {}
348
+ end
349
+
350
+ it 'returns an empty array' do
351
+ assert_empty @controller.current_members
352
+ end
353
+ end
354
+ end
355
+
356
+ describe 'render_authenticate_error (group)' do
357
+ before do
358
+ get '/demo/members_only_group', params: {}, headers: {}
359
+ end
360
+
361
+ it 'returns 401 status' do
362
+ assert_equal 401, response.status
363
+ end
364
+
365
+ it 'returns a JSON body with an errors key containing unauthenticated message' do
366
+ body = JSON.parse(response.body)
367
+ assert_includes body['errors'], I18n.t('devise.failure.unauthenticated')
368
+ end
369
+ end
370
+ end
371
+
372
+ # ------------------------------------------------------------------
373
+ # log_process_action – ClassMethods override
374
+ # Sets payload[:status] to 401 when no status is present and no
375
+ # exception is raised.
376
+ # ------------------------------------------------------------------
377
+ describe 'ClassMethods#log_process_action' do
378
+ let(:controller_class) { DemoUserController }
379
+
380
+ it 'sets status to 401 when payload has no status and no exception' do
381
+ payload = {}
382
+ controller_class.log_process_action(payload)
383
+ assert_equal 401, payload[:status]
384
+ end
385
+
386
+ it 'preserves an existing status in the payload' do
387
+ payload = { status: 200 }
388
+ controller_class.log_process_action(payload)
389
+ assert_equal 200, payload[:status]
390
+ end
391
+
392
+ it 'does not set status when an exception is present' do
393
+ payload = { exception: ['RuntimeError', 'boom'] }
394
+ controller_class.log_process_action(payload)
395
+ refute payload.key?(:status), 'status should not be set when an exception is present'
396
+ end
397
+
398
+ it 'is defined on the controller class' do
399
+ assert controller_class.respond_to?(:log_process_action)
400
+ end
401
+ end
402
+ end
@@ -22,9 +22,9 @@ class DeviseTokenAuth::TokenFactoryTest < ActiveSupport::TestCase
22
22
  assert_equal(secure_string.size, 22)
23
23
  assert_match(token_regexp, secure_string)
24
24
 
25
- SecureRandom.stub(:urlsafe_base64, secure_string) do
26
- assert_equal(tf.secure_string, secure_string)
27
- end
25
+ SecureRandom.stubs(:urlsafe_base64).returns(secure_string)
26
+ assert_equal(tf.secure_string, secure_string)
27
+ SecureRandom.unstub(:urlsafe_base64)
28
28
  end
29
29
 
30
30
  it '::client' do
@@ -35,9 +35,9 @@ class DeviseTokenAuth::TokenFactoryTest < ActiveSupport::TestCase
35
35
  assert_match(token_regexp, client)
36
36
 
37
37
  secure_string = tf.secure_string
38
- tf.stub(:secure_string, secure_string) do
39
- assert_equal(tf.client, secure_string)
40
- end
38
+ tf.stubs(:secure_string).returns(secure_string)
39
+ assert_equal(tf.client, secure_string)
40
+ tf.unstub(:secure_string)
41
41
  end
42
42
 
43
43
  it '::token' do
@@ -49,9 +49,9 @@ class DeviseTokenAuth::TokenFactoryTest < ActiveSupport::TestCase
49
49
  assert_match(token_regexp, token)
50
50
 
51
51
  secure_string = tf.secure_string
52
- tf.stub(:secure_string, secure_string) do
53
- assert_equal(tf.token, secure_string)
54
- end
52
+ tf.stubs(:secure_string).returns(secure_string)
53
+ assert_equal(tf.token, secure_string)
54
+ tf.unstub(:secure_string)
55
55
  end
56
56
 
57
57
  it '::token_hash(args)' do
@@ -84,12 +84,12 @@ class DeviseTokenAuth::TokenFactoryTest < ActiveSupport::TestCase
84
84
 
85
85
  it '::expiry(args)' do
86
86
  time = Time.now
87
- Time.stub(:now, time) do
88
- assert_equal(tf.expiry(lifespan), (time + lifespan).to_i)
87
+ Time.stubs(:now).returns(time)
88
+ assert_equal(tf.expiry(lifespan), (time + lifespan).to_i)
89
89
 
90
- lifespan = nil
91
- assert_equal(tf.expiry(lifespan), (time + DeviseTokenAuth.token_lifespan).to_i)
92
- end
90
+ lifespan = nil
91
+ assert_equal(tf.expiry(lifespan), (time + DeviseTokenAuth.token_lifespan).to_i)
92
+ Time.unstub(:now)
93
93
  end
94
94
 
95
95
  it '::create' do
@@ -106,10 +106,10 @@ class DeviseTokenAuth::TokenFactoryTest < ActiveSupport::TestCase
106
106
  assert_equal(token.client, client)
107
107
 
108
108
  time = Time.now
109
- Time.stub(:now, time) do
110
- token = tf.create(lifespan: lifespan)
111
- assert_equal(token.expiry, (time + lifespan).to_i)
112
- end
109
+ Time.stubs(:now).returns(time)
110
+ token = tf.create(lifespan: lifespan)
111
+ assert_equal(token.expiry, (time + lifespan).to_i)
112
+ Time.unstub(:now)
113
113
 
114
114
  token = tf.create(cost: cost)
115
115
  token_cost = token_hash_cost_regexp.match(token.token_hash)[1].to_i
@@ -213,5 +213,65 @@ module DeviseTokenAuth
213
213
  end
214
214
  end
215
215
  end
216
+
217
+ describe 'rails api application controller' do
218
+ setup :prepare_destination
219
+
220
+ before do
221
+ @dir = File.join(destination_root, 'app', 'controllers')
222
+ @fname = File.join(@dir, 'application_controller.rb')
223
+ FileUtils.mkdir_p(@dir)
224
+
225
+ File.open(@fname, 'w') do |f|
226
+ f.write <<-RUBY
227
+ class ApplicationController < ActionController::API
228
+ def whatever
229
+ 'whatever'
230
+ end
231
+ end
232
+ RUBY
233
+ end
234
+
235
+ run_generator
236
+ end
237
+
238
+ test 'controller concern is appended to rails api application controller' do
239
+ assert_file 'app/controllers/application_controller.rb' do |controller|
240
+ assert_match(/include DeviseTokenAuth::Concerns::SetUserByToken/, controller)
241
+ end
242
+ end
243
+
244
+ test 'subsequent runs do not modify rails api application controller' do
245
+ run_generator
246
+ assert_file 'app/controllers/application_controller.rb' do |controller|
247
+ matches = controller.scan(/include DeviseTokenAuth::Concerns::SetUserByToken/m).size
248
+ assert_equal 1, matches
249
+ end
250
+ end
251
+ end
252
+
253
+ describe 'missing application controller' do
254
+ setup :prepare_destination
255
+
256
+ before do
257
+ run_generator
258
+ end
259
+
260
+ test 'generator does not raise when application_controller.rb is absent' do
261
+ assert_no_file 'app/controllers/application_controller.rb'
262
+ end
263
+ end
264
+
265
+ describe 'missing routes file' do
266
+ setup :prepare_destination
267
+
268
+ before do
269
+ run_generator
270
+ end
271
+
272
+ test 'generator does not raise when config/routes.rb is absent' do
273
+ assert_no_file 'config/routes.rb'
274
+ end
275
+ end
216
276
  end
217
277
  end
@@ -6,7 +6,7 @@ require 'generators/devise_token_auth/install_generator' if DEVISE_TOKEN_AUTH_OR
6
6
  require 'generators/devise_token_auth/install_mongoid_generator' if DEVISE_TOKEN_AUTH_ORM == :mongoid
7
7
 
8
8
  module DeviseTokenAuth
9
- class InstallGeneratorTest < Rails::Generators::TestCase
9
+ class InstallGeneratorWithNamespaceTest < Rails::Generators::TestCase
10
10
  tests InstallGenerator if DEVISE_TOKEN_AUTH_ORM == :active_record
11
11
  tests InstallMongoidGenerator if DEVISE_TOKEN_AUTH_ORM == :mongoid
12
12
  destination Rails.root.join('tmp/generators')