propel_authentication 0.2.1 → 0.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/lib/generators/propel_authentication/install_generator.rb +20 -6
- data/lib/generators/propel_authentication/templates/auth/passwords_controller.rb.tt +9 -9
- data/lib/generators/propel_authentication/templates/auth/signup_controller.rb.tt +3 -3
- data/lib/generators/propel_authentication/templates/auth/tokens_controller.rb.tt +3 -3
- data/lib/generators/propel_authentication/templates/db/migrate/create_agencies.rb +2 -2
- data/lib/generators/propel_authentication/templates/db/migrate/create_organizations.rb +4 -2
- data/lib/generators/propel_authentication/templates/db/migrate/create_users.rb +2 -2
- data/lib/generators/propel_authentication/templates/models/agency.rb.tt +4 -2
- data/lib/generators/propel_authentication/templates/models/agent.rb.tt +4 -2
- data/lib/generators/propel_authentication/templates/models/organization.rb.tt +12 -2
- data/lib/generators/propel_authentication/templates/models/user.rb.tt +18 -2
- data/lib/generators/propel_authentication/templates/test/controllers/auth/lockable_integration_test.rb.tt +1 -1
- data/lib/generators/propel_authentication/templates/test/controllers/auth/password_reset_integration_test.rb.tt +8 -8
- data/lib/generators/propel_authentication/templates/test/controllers/auth/signup_controller_test.rb.tt +6 -6
- data/lib/generators/propel_authentication/templates/test/controllers/auth/tokens_controller_test.rb.tt +1 -1
- data/lib/generators/propel_authentication/test/generators/authentication/controllers/tokens_controller_test.rb +1 -1
- data/lib/generators/propel_authentication/test/generators/authentication/install_generator_test.rb +1 -1
- data/lib/generators/propel_authentication/test/integration/multi_version_generator_test.rb +12 -13
- data/lib/propel_authentication.rb +1 -1
- metadata +24 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: feff8cf5d61966deceb32c0466338c47270c96b06d67304aeeab26304402f83f
|
4
|
+
data.tar.gz: 9a5d2b1e807454d4223524dad81b109dd97a655a7ce0512a49c8d22c65c9ddff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18219d594b8084f6dc283d2e5d034413f69492c3ca9861588c40170659586150f118acf23bc9003356144704a4648c84b8265dafbd81e9bad8fc722779b4fd93
|
7
|
+
data.tar.gz: 2bcf4ca9a1779fb6487d9e31e28e5035cc71771e1f7983501b1697fd94b78441f849776e76dc73f4c895d84ac739e2bc91c6b0624a06d1ea9b163e4b02c653e2
|
data/CHANGELOG.md
CHANGED
@@ -13,6 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
13
13
|
- Session management and device tracking
|
14
14
|
- Advanced password policies
|
15
15
|
|
16
|
+
## [0.3.0] - 2025-01-15
|
17
|
+
|
18
|
+
### 🔧 Compatibility Updates
|
19
|
+
- **PropelApi Integration**: Updated to work seamlessly with PropelApi 0.3.0's new polymorphic association features
|
20
|
+
- **Test Template Compatibility**: Authentication templates now compatible with enhanced polymorphic test generation
|
21
|
+
- **Dependency Updates**: Bumped version to maintain compatibility with PropelApi 0.3.0
|
22
|
+
|
23
|
+
### 🐛 Bug Fixes
|
24
|
+
- **Generator Compatibility**: Fixed potential conflicts with PropelApi's enhanced generator argument processing
|
25
|
+
- **Template Consistency**: Ensured all authentication templates follow the same patterns as PropelApi 0.3.0
|
26
|
+
|
16
27
|
## [0.2.1] - 2025-01-14
|
17
28
|
|
18
29
|
### Changed
|
@@ -116,8 +116,8 @@ module PropelAuthentication
|
|
116
116
|
|
117
117
|
def add_authentication_gems
|
118
118
|
add_gem_if_missing('bcrypt', '~> 3.1.20')
|
119
|
-
add_gem_if_missing('jwt', '~> 2
|
120
|
-
add_gem_if_missing('letter_opener', '~> 1.
|
119
|
+
add_gem_if_missing('jwt', '~> 3.1.2')
|
120
|
+
add_gem_if_missing('letter_opener', '~> 1.10', group: :development)
|
121
121
|
end
|
122
122
|
|
123
123
|
def add_authentication_routes
|
@@ -264,8 +264,10 @@ module PropelAuthentication
|
|
264
264
|
name: "Acme Corporation"
|
265
265
|
website: "https://acme-corp.com"
|
266
266
|
time_zone: "UTC"
|
267
|
-
|
268
|
-
|
267
|
+
logo: "https://acme-corp.com/logo.png"
|
268
|
+
slug: "acme-corporation"
|
269
|
+
metadata: { org_type: "enterprise", industry: "technology", size: "large" }
|
270
|
+
settings: { theme: "corporate", timezone: "EST", features: "premium" }
|
269
271
|
created_at: <%= 30.days.ago %>
|
270
272
|
updated_at: <%= 1.day.ago %>
|
271
273
|
|
@@ -273,8 +275,10 @@ module PropelAuthentication
|
|
273
275
|
name: "Tech Startup Inc"
|
274
276
|
website: "https://techstartup.io"
|
275
277
|
time_zone: "America/New_York"
|
276
|
-
|
277
|
-
|
278
|
+
logo: "https://techstartup.io/logo.png"
|
279
|
+
slug: "tech-startup-inc"
|
280
|
+
metadata: { org_type: "startup", industry: "software", size: "small" }
|
281
|
+
settings: { theme: "modern", timezone: "PST", features: "basic" }
|
278
282
|
created_at: <%= 15.days.ago %>
|
279
283
|
updated_at: <%= 2.days.ago %>
|
280
284
|
FIXTURE
|
@@ -293,6 +297,8 @@ module PropelAuthentication
|
|
293
297
|
confirmed_at: null
|
294
298
|
confirmation_token: "<%= SecureRandom.hex(32) %>"
|
295
299
|
confirmation_sent_at: <%= 1.hour.ago %>
|
300
|
+
metadata: { user_type: "admin", department: "engineering", priority: "high" }
|
301
|
+
settings: { theme: "dark", language: "en", notifications: true }
|
296
302
|
created_at: <%= 7.days.ago %>
|
297
303
|
updated_at: <%= 1.day.ago %>
|
298
304
|
|
@@ -307,6 +313,8 @@ module PropelAuthentication
|
|
307
313
|
confirmed_at: null
|
308
314
|
failed_login_attempts: 0
|
309
315
|
locked_at: null
|
316
|
+
metadata: { user_type: "manager", department: "marketing", priority: "high" }
|
317
|
+
settings: { theme: "light", language: "en", notifications: false }
|
310
318
|
created_at: <%= 5.days.ago %>
|
311
319
|
updated_at: <%= 1.day.ago %>
|
312
320
|
|
@@ -319,6 +327,8 @@ module PropelAuthentication
|
|
319
327
|
organization: acme_org
|
320
328
|
status: "active"
|
321
329
|
confirmed_at: <%= 7.days.ago %>
|
330
|
+
metadata: { user_type: "employee", department: "sales", priority: "medium" }
|
331
|
+
settings: { theme: "auto", language: "es", notifications: true }
|
322
332
|
created_at: <%= 14.days.ago %>
|
323
333
|
updated_at: <%= 1.day.ago %>
|
324
334
|
|
@@ -333,6 +343,8 @@ module PropelAuthentication
|
|
333
343
|
confirmed_at: <%= 10.days.ago %>
|
334
344
|
failed_login_attempts: 5
|
335
345
|
locked_at: <%= 1.hour.ago %>
|
346
|
+
metadata: { user_type: "employee", department: "support", priority: "low" }
|
347
|
+
settings: { theme: "light", language: "en", notifications: false }
|
336
348
|
created_at: <%= 20.days.ago %>
|
337
349
|
updated_at: <%= 1.hour.ago %>
|
338
350
|
|
@@ -347,6 +359,8 @@ module PropelAuthentication
|
|
347
359
|
confirmed_at: null
|
348
360
|
confirmation_token: "<%= SecureRandom.hex(32) %>"
|
349
361
|
confirmation_sent_at: <%= 25.hours.ago %>
|
362
|
+
metadata: { user_type: "test", department: "qa", priority: "low" }
|
363
|
+
settings: { theme: "dark", language: "fr", notifications: false }
|
350
364
|
created_at: <%= 30.days.ago %>
|
351
365
|
updated_at: <%= 25.hours.ago %>
|
352
366
|
FIXTURE
|
@@ -10,12 +10,12 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
|
|
10
10
|
|
11
11
|
# Validate email_address parameter
|
12
12
|
if email_address.blank?
|
13
|
-
return render json: { error: "Email address is required" }, status: :
|
13
|
+
return render json: { error: "Email address is required" }, status: :unprocessable_content
|
14
14
|
end
|
15
15
|
|
16
16
|
# Validate email format
|
17
17
|
unless email_address.match?(URI::MailTo::EMAIL_REGEXP)
|
18
|
-
return render json: { error: "Email address format is invalid" }, status: :
|
18
|
+
return render json: { error: "Email address format is invalid" }, status: :unprocessable_content
|
19
19
|
end
|
20
20
|
|
21
21
|
user = User.find_by(email_address: email_address)
|
@@ -46,7 +46,7 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
|
|
46
46
|
end
|
47
47
|
rescue => e
|
48
48
|
Rails.logger.error "Password reset creation error: #{e.message}"
|
49
|
-
render json: { error: "Unable to process password reset request" }, status: :
|
49
|
+
render json: { error: "Unable to process password reset request" }, status: :unprocessable_content
|
50
50
|
end
|
51
51
|
|
52
52
|
# GET <%= auth_route_prefix %>/reset
|
@@ -54,7 +54,7 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
|
|
54
54
|
token = params[:token]
|
55
55
|
|
56
56
|
if token.blank?
|
57
|
-
render json: { error: 'Reset token is required' }, status: :
|
57
|
+
render json: { error: 'Reset token is required' }, status: :unprocessable_content
|
58
58
|
return
|
59
59
|
end
|
60
60
|
|
@@ -89,15 +89,15 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
|
|
89
89
|
|
90
90
|
# Validate required parameters
|
91
91
|
if token.blank?
|
92
|
-
return render json: { error: 'Reset token is required' }, status: :
|
92
|
+
return render json: { error: 'Reset token is required' }, status: :unprocessable_content
|
93
93
|
end
|
94
94
|
|
95
95
|
if new_password.blank?
|
96
|
-
return render json: { error: 'New password is required' }, status: :
|
96
|
+
return render json: { error: 'New password is required' }, status: :unprocessable_content
|
97
97
|
end
|
98
98
|
|
99
99
|
if new_password != password_confirmation
|
100
|
-
return render json: { error: 'Password confirmation does not match password' }, status: :
|
100
|
+
return render json: { error: 'Password confirmation does not match password' }, status: :unprocessable_content
|
101
101
|
end
|
102
102
|
|
103
103
|
user = User.find_by_jwt_password_reset_token(token)
|
@@ -123,10 +123,10 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
|
|
123
123
|
render json: {
|
124
124
|
error: primary_error, # Use specific validation message
|
125
125
|
details: error_messages
|
126
|
-
}, status: :
|
126
|
+
}, status: :unprocessable_content
|
127
127
|
end
|
128
128
|
rescue => e
|
129
129
|
Rails.logger.error "Password reset update error: #{e.message}"
|
130
|
-
render json: { error: 'Unable to reset password' }, status: :
|
130
|
+
render json: { error: 'Unable to reset password' }, status: :unprocessable_content
|
131
131
|
end
|
132
132
|
end
|
@@ -41,7 +41,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
|
|
41
41
|
error: 'Validation failed',
|
42
42
|
details: extract_validation_errors(e),
|
43
43
|
message: 'Please correct the errors and try again'
|
44
|
-
}, status: :
|
44
|
+
}, status: :unprocessable_content
|
45
45
|
rescue => e
|
46
46
|
render json: {
|
47
47
|
error: 'Account creation failed',
|
@@ -224,7 +224,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
|
|
224
224
|
message: 'Agency details must be provided when agency tenancy is enabled',
|
225
225
|
code: 'MISSING_AGENCY_DATA',
|
226
226
|
hint: 'Include an "agency" object with name and other details in your request'
|
227
|
-
}, status: :
|
227
|
+
}, status: :unprocessable_content
|
228
228
|
return false
|
229
229
|
end
|
230
230
|
|
@@ -233,7 +233,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
|
|
233
233
|
error: 'Agency name required',
|
234
234
|
message: 'Agency name is required when creating an agency',
|
235
235
|
code: 'MISSING_AGENCY_NAME'
|
236
|
-
}, status: :
|
236
|
+
}, status: :unprocessable_content
|
237
237
|
return false
|
238
238
|
end
|
239
239
|
|
@@ -42,7 +42,7 @@ class <%= auth_controller_class_name('tokens') %> < ApplicationController
|
|
42
42
|
render json: { error: 'Invalid credentials' }, status: :unauthorized
|
43
43
|
end
|
44
44
|
rescue ActionController::ParameterMissing
|
45
|
-
render json: { error: 'Missing required parameters' }, status: :
|
45
|
+
render json: { error: 'Missing required parameters' }, status: :unprocessable_content
|
46
46
|
end
|
47
47
|
|
48
48
|
# DELETE <%= auth_route_prefix %>/logout
|
@@ -69,7 +69,7 @@ class <%= auth_controller_class_name('tokens') %> < ApplicationController
|
|
69
69
|
token = params[:token]
|
70
70
|
|
71
71
|
if token.blank?
|
72
|
-
render json: { error: 'Token is required' }, status: :
|
72
|
+
render json: { error: 'Token is required' }, status: :unprocessable_content
|
73
73
|
return
|
74
74
|
end
|
75
75
|
|
@@ -107,7 +107,7 @@ class <%= auth_controller_class_name('tokens') %> < ApplicationController
|
|
107
107
|
|
108
108
|
def validate_login_parameters
|
109
109
|
unless params[:user].present? && params[:user][:email_address].present? && params[:user][:password].present?
|
110
|
-
render json: { error: 'Email address and password are required' }, status: :
|
110
|
+
render json: { error: 'Email address and password are required' }, status: :unprocessable_content
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
@@ -7,10 +7,10 @@ class CreateAgencies < ActiveRecord::Migration[8.0]
|
|
7
7
|
t.string :address
|
8
8
|
t.string :time_zone
|
9
9
|
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with?('postgresql')
|
10
|
-
t.jsonb :
|
10
|
+
t.jsonb :metadata, default: {}
|
11
11
|
t.jsonb :settings, default: {}
|
12
12
|
else
|
13
|
-
t.json :
|
13
|
+
t.json :metadata, default: {}
|
14
14
|
t.json :settings, default: {}
|
15
15
|
end
|
16
16
|
|
@@ -4,11 +4,13 @@ class CreateOrganizations < ActiveRecord::Migration[8.0]
|
|
4
4
|
t.string :name, null: false
|
5
5
|
t.string :website
|
6
6
|
t.string :time_zone
|
7
|
+
t.string :logo
|
8
|
+
t.string :slug
|
7
9
|
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with?('postgresql')
|
8
|
-
t.jsonb :
|
10
|
+
t.jsonb :metadata, default: {}
|
9
11
|
t.jsonb :settings, default: {}
|
10
12
|
else
|
11
|
-
t.json :
|
13
|
+
t.json :metadata, default: {}
|
12
14
|
t.json :settings, default: {}
|
13
15
|
end
|
14
16
|
|
@@ -26,10 +26,10 @@ class CreateUsers < ActiveRecord::Migration[8.0]
|
|
26
26
|
t.references :organization, null: false, foreign_key: true
|
27
27
|
|
28
28
|
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with?('postgresql')
|
29
|
-
t.jsonb :
|
29
|
+
t.jsonb :metadata, default: {}
|
30
30
|
t.jsonb :settings, default: {}
|
31
31
|
else
|
32
|
-
t.json :
|
32
|
+
t.json :metadata, default: {}
|
33
33
|
t.json :settings, default: {}
|
34
34
|
end
|
35
35
|
|
@@ -7,7 +7,9 @@ class Agency < ApplicationRecord
|
|
7
7
|
<% if @rendering_engine == 'json_facet' -%>
|
8
8
|
|
9
9
|
# Facets
|
10
|
-
json_facet :short,
|
11
|
-
|
10
|
+
json_facet :short,
|
11
|
+
fields: [:id, :name]
|
12
|
+
json_facet :details,
|
13
|
+
fields: [:id, :name, :organization_id, :created_at, :updated_at]
|
12
14
|
<% end -%>
|
13
15
|
end
|
@@ -7,7 +7,9 @@ class Agent < ApplicationRecord
|
|
7
7
|
<% if @rendering_engine == 'json_facet' -%>
|
8
8
|
|
9
9
|
# Facets
|
10
|
-
json_facet :short,
|
11
|
-
|
10
|
+
json_facet :short,
|
11
|
+
fields: [:id, :title]
|
12
|
+
json_facet :details,
|
13
|
+
fields: [:id, :title, :role, :organization_id, :created_at, :updated_at]
|
12
14
|
<% end -%>
|
13
15
|
end
|
@@ -6,7 +6,17 @@ class Organization < ApplicationRecord
|
|
6
6
|
validates :name, presence: true
|
7
7
|
<% if @rendering_engine == 'json_facet' -%>
|
8
8
|
# Facets
|
9
|
-
json_facet :short,
|
10
|
-
|
9
|
+
json_facet :short,
|
10
|
+
fields:
|
11
|
+
[
|
12
|
+
:id, :name, :website, :time_zone, :logo, :slug
|
13
|
+
]
|
14
|
+
json_facet :details,
|
15
|
+
fields:
|
16
|
+
[
|
17
|
+
:id, :name, :website, :time_zone, :logo, :slug,
|
18
|
+
:created_at, :updated_at,
|
19
|
+
:metadata, :settings
|
20
|
+
]
|
11
21
|
<% end -%>
|
12
22
|
end
|
@@ -21,6 +21,22 @@ class User < ApplicationRecord
|
|
21
21
|
# include Statusable
|
22
22
|
|
23
23
|
# Facets
|
24
|
-
json_facet :short,
|
25
|
-
|
24
|
+
json_facet :short,
|
25
|
+
fields:
|
26
|
+
[
|
27
|
+
:id, :email_address, :username, :phone_number,
|
28
|
+
:first_name, :middle_name, :last_name,
|
29
|
+
:time_zone, :status
|
30
|
+
]
|
31
|
+
json_facet :details,
|
32
|
+
fields:
|
33
|
+
[
|
34
|
+
:id, :email_address, :username, :phone_number,
|
35
|
+
:first_name, :middle_name, :last_name,
|
36
|
+
:time_zone, :status,
|
37
|
+
:confirmation_sent_at, :unconfirmed_email_address, :confirmed_at,
|
38
|
+
:last_login_at, :failed_login_attempts, :locked_at,
|
39
|
+
:created_at, :updated_at,
|
40
|
+
:organization_id, :metadata, :settings
|
41
|
+
], include: [:organization]
|
26
42
|
end
|
@@ -148,7 +148,7 @@ class <%= controller_namespace('tokens') %>LockableIntegrationTest < ActionDispa
|
|
148
148
|
|
149
149
|
post '<%= auth_route_prefix %>/unlock', params: {}
|
150
150
|
|
151
|
-
assert_response :
|
151
|
+
assert_response :unprocessable_content, "Missing token should return 422"
|
152
152
|
|
153
153
|
json = JSON.parse(response.body)
|
154
154
|
assert_match(/token.*required/i, json['error'], "Should indicate token is required")
|
@@ -39,7 +39,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
39
39
|
post '<%= auth_route_prefix %>/reset', params: { email_address: "invalid-email-format" }
|
40
40
|
|
41
41
|
# VERIFY VALIDATION ERROR: Should return validation error
|
42
|
-
assert_response :
|
42
|
+
assert_response :unprocessable_content, "Invalid email_address format should be rejected"
|
43
43
|
|
44
44
|
response_json = JSON.parse(response.body)
|
45
45
|
assert_match(/email.*invalid/i, response_json['error'], "Should indicate email_address format error")
|
@@ -65,7 +65,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
65
65
|
post '<%= auth_route_prefix %>/reset', params: {}
|
66
66
|
|
67
67
|
# VERIFY PARAMETER VALIDATION: Should return parameter error
|
68
|
-
assert_response :
|
68
|
+
assert_response :unprocessable_content, "Missing email_address should return validation error"
|
69
69
|
|
70
70
|
response_json = JSON.parse(response.body)
|
71
71
|
assert_match(/email.*required/i, response_json['error'], "Should indicate email_address is required")
|
@@ -181,7 +181,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
181
181
|
}
|
182
182
|
|
183
183
|
# VERIFY VALIDATION: Should return validation error
|
184
|
-
assert_response :
|
184
|
+
assert_response :unprocessable_content, "Mismatched passwords should be rejected"
|
185
185
|
|
186
186
|
response_json = JSON.parse(response.body)
|
187
187
|
assert_match(/password.*confirmation.*match/i, response_json['error'], "Should indicate password mismatch")
|
@@ -205,7 +205,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
205
205
|
}
|
206
206
|
|
207
207
|
# VERIFY VALIDATION: Should return validation error
|
208
|
-
assert_response :
|
208
|
+
assert_response :unprocessable_content, "Weak password should be rejected"
|
209
209
|
|
210
210
|
response_json = JSON.parse(response.body)
|
211
211
|
assert_match(/password.*too short/i, response_json['error'], "Should indicate password strength issue")
|
@@ -226,7 +226,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
226
226
|
password_confirmation: "newpassword123"
|
227
227
|
}
|
228
228
|
|
229
|
-
assert_response :
|
229
|
+
assert_response :unprocessable_content, "Missing token should be rejected"
|
230
230
|
|
231
231
|
# TEST MISSING PASSWORD
|
232
232
|
patch '<%= auth_route_prefix %>/reset', params: {
|
@@ -234,7 +234,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
234
234
|
password_confirmation: "newpassword123"
|
235
235
|
}
|
236
236
|
|
237
|
-
assert_response :
|
237
|
+
assert_response :unprocessable_content, "Missing password should be rejected"
|
238
238
|
|
239
239
|
# TEST MISSING CONFIRMATION
|
240
240
|
patch '<%= auth_route_prefix %>/reset', params: {
|
@@ -242,7 +242,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
242
242
|
password: "newpassword123"
|
243
243
|
}
|
244
244
|
|
245
|
-
assert_response :
|
245
|
+
assert_response :unprocessable_content, "Missing password confirmation should be rejected"
|
246
246
|
end
|
247
247
|
|
248
248
|
test "should clear failed login attempts on successful password reset" do
|
@@ -356,7 +356,7 @@ class <%= controller_namespace('passwords') %>PasswordResetIntegrationTest < Act
|
|
356
356
|
get '<%= auth_route_prefix %>/reset', params: {}
|
357
357
|
|
358
358
|
# VERIFY PARAMETER VALIDATION: Should return parameter error
|
359
|
-
assert_response :
|
359
|
+
assert_response :unprocessable_content, "Missing token should return validation error"
|
360
360
|
|
361
361
|
response_json = JSON.parse(response.body)
|
362
362
|
assert_match(/token.*required/i, response_json['error'], "Should indicate token is required")
|
@@ -111,7 +111,7 @@ class <%= controller_namespace('signup') %>SignupControllerTest < ActionDispatch
|
|
111
111
|
params: invalid_params,
|
112
112
|
as: :json
|
113
113
|
|
114
|
-
assert_response :
|
114
|
+
assert_response :unprocessable_content
|
115
115
|
response_body = JSON.parse(response.body)
|
116
116
|
assert_includes response_body.keys, 'error'
|
117
117
|
end
|
@@ -123,7 +123,7 @@ class <%= controller_namespace('signup') %>SignupControllerTest < ActionDispatch
|
|
123
123
|
params: invalid_params,
|
124
124
|
as: :json
|
125
125
|
|
126
|
-
assert_response :
|
126
|
+
assert_response :unprocessable_content
|
127
127
|
response_body = JSON.parse(response.body)
|
128
128
|
assert_includes response_body.keys, 'error'
|
129
129
|
end
|
@@ -136,7 +136,7 @@ class <%= controller_namespace('signup') %>SignupControllerTest < ActionDispatch
|
|
136
136
|
params: invalid_params,
|
137
137
|
as: :json
|
138
138
|
|
139
|
-
assert_response :
|
139
|
+
assert_response :unprocessable_content
|
140
140
|
response_body = JSON.parse(response.body)
|
141
141
|
assert_includes response_body.keys, 'details'
|
142
142
|
assert_includes response_body['details'].keys, 'email_address'
|
@@ -150,7 +150,7 @@ class <%= controller_namespace('signup') %>SignupControllerTest < ActionDispatch
|
|
150
150
|
params: invalid_params,
|
151
151
|
as: :json
|
152
152
|
|
153
|
-
assert_response :
|
153
|
+
assert_response :unprocessable_content
|
154
154
|
response_body = JSON.parse(response.body)
|
155
155
|
assert_includes response_body.keys, 'details'
|
156
156
|
end
|
@@ -172,7 +172,7 @@ class <%= controller_namespace('signup') %>SignupControllerTest < ActionDispatch
|
|
172
172
|
params: duplicate_params,
|
173
173
|
as: :json
|
174
174
|
|
175
|
-
assert_response :
|
175
|
+
assert_response :unprocessable_content
|
176
176
|
response_body = JSON.parse(response.body)
|
177
177
|
assert_includes response_body.keys, 'details'
|
178
178
|
assert_includes response_body['details'].keys, 'email_address'
|
@@ -186,7 +186,7 @@ class <%= controller_namespace('signup') %>SignupControllerTest < ActionDispatch
|
|
186
186
|
params: @valid_signup_params,
|
187
187
|
as: :json
|
188
188
|
|
189
|
-
assert_response :
|
189
|
+
assert_response :unprocessable_content
|
190
190
|
response_body = JSON.parse(response.body)
|
191
191
|
assert_equal 'MISSING_AGENCY_DATA', response_body['code']
|
192
192
|
end
|
@@ -232,7 +232,7 @@ class <%= controller_namespace('tokens') %>TokensControllerTest < ActionDispatch
|
|
232
232
|
}
|
233
233
|
|
234
234
|
# VERIFY PARAMETER VALIDATION: Check required field enforcement
|
235
|
-
assert_response :
|
235
|
+
assert_response :unprocessable_content, "Missing required parameters should return unprocessable_content"
|
236
236
|
response_json = JSON.parse(response.body)
|
237
237
|
assert response_json["error"].present?, "Should return validation error message"
|
238
238
|
end
|
@@ -72,7 +72,7 @@ class TokensControllerTest < ActionDispatch::IntegrationTest
|
|
72
72
|
}
|
73
73
|
}, as: :json
|
74
74
|
|
75
|
-
assert_response :
|
75
|
+
assert_response :unprocessable_content
|
76
76
|
|
77
77
|
response_body = JSON.parse(response.body)
|
78
78
|
assert response_body.key?("error"), "Should return error message"
|
data/lib/generators/propel_authentication/test/generators/authentication/install_generator_test.rb
CHANGED
@@ -151,7 +151,7 @@ class Propel::Authentication::InstallGeneratorTest < Rails::Generators::TestCase
|
|
151
151
|
assert_match(/t\.references :organization/, migration)
|
152
152
|
|
153
153
|
# JSON fields for flexible data storage
|
154
|
-
assert_match(/t\.jsonb :
|
154
|
+
assert_match(/t\.jsonb :metadata, default: {}/, migration)
|
155
155
|
assert_match(/t\.jsonb :settings, default: {}/, migration)
|
156
156
|
|
157
157
|
# Proper indexes for JWT authentication performance
|
@@ -16,32 +16,31 @@ class MultiVersionGeneratorTest < Rails::Generators::TestCase
|
|
16
16
|
super
|
17
17
|
end
|
18
18
|
|
19
|
-
test "generator creates dynamic
|
20
|
-
run_generator ["--
|
19
|
+
test "generator creates dynamic API versioning structure" do
|
20
|
+
run_generator ["--configurable-versioning"]
|
21
21
|
|
22
|
-
# Verify
|
23
|
-
assert_file "app/controllers/api/
|
24
|
-
assert_match(/class Api::
|
25
|
-
assert_match(/POST \/api\/
|
22
|
+
# Verify base controllers are created
|
23
|
+
assert_file "app/controllers/api/auth/base_tokens_controller.rb" do |content|
|
24
|
+
assert_match(/class Api::Auth::BaseTokensController < ApplicationController/, content)
|
25
|
+
assert_match(/POST \/api\/\{version\}\/auth\/login/, content)
|
26
26
|
assert_match(/def create/, content)
|
27
27
|
assert_match(/def show/, content)
|
28
28
|
assert_match(/def destroy/, content)
|
29
29
|
assert_match(/def unlock/, content)
|
30
30
|
end
|
31
31
|
|
32
|
-
assert_file "app/controllers/api/
|
33
|
-
assert_match(/class Api::
|
34
|
-
assert_match(/POST \/api\/
|
32
|
+
assert_file "app/controllers/api/auth/base_passwords_controller.rb" do |content|
|
33
|
+
assert_match(/class Api::Auth::BasePasswordsController < ApplicationController/, content)
|
34
|
+
assert_match(/POST \/api\/\{version\}\/auth\/reset/, content)
|
35
35
|
assert_match(/def create/, content)
|
36
36
|
assert_match(/def show/, content)
|
37
37
|
assert_match(/def update/, content)
|
38
38
|
end
|
39
39
|
|
40
|
-
# Verify routes are created
|
40
|
+
# Verify runtime configurable routes are created
|
41
41
|
assert_file "config/routes.rb" do |content|
|
42
|
-
assert_match(
|
43
|
-
assert_match(/
|
44
|
-
assert_match(/post 'login', to: 'tokens#create', as: :login/, content)
|
42
|
+
assert_match(/# Runtime configurable API versioning routes/, content)
|
43
|
+
assert_match(/api_version = PropelAccess\.configuration\.api_version/, content)
|
45
44
|
assert_match(/namespace :api do/, content)
|
46
45
|
assert_match(/namespace api_version do/, content)
|
47
46
|
assert_match(/namespace :auth do/, content)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: propel_authentication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Propel Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-09-
|
11
|
+
date: 2025-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -50,14 +50,34 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 3.1.2
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: 3.1.2
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: noticed
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 2.0.0
|
68
|
+
- - "<"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '3.0'
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.0.0
|
78
|
+
- - "<"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '3.0'
|
61
81
|
description: A self-extracting generator that creates a JWT-based authentication system
|
62
82
|
with agencies, agents, password resets, email confirmation, and account locking
|
63
83
|
for Rails applications.
|