propel_authentication 0.2.0 → 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.
Files changed (22) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/lib/generators/propel_authentication/install_generator.rb +20 -6
  4. data/lib/generators/propel_authentication/templates/auth/passwords_controller.rb.tt +9 -9
  5. data/lib/generators/propel_authentication/templates/auth/signup_controller.rb.tt +3 -3
  6. data/lib/generators/propel_authentication/templates/auth/tokens_controller.rb.tt +3 -3
  7. data/lib/generators/propel_authentication/templates/db/migrate/create_agencies.rb +2 -2
  8. data/lib/generators/propel_authentication/templates/db/migrate/create_organizations.rb +4 -2
  9. data/lib/generators/propel_authentication/templates/db/migrate/create_users.rb +2 -2
  10. data/lib/generators/propel_authentication/templates/models/agency.rb.tt +4 -2
  11. data/lib/generators/propel_authentication/templates/models/agent.rb.tt +4 -2
  12. data/lib/generators/propel_authentication/templates/models/organization.rb.tt +12 -2
  13. data/lib/generators/propel_authentication/templates/models/user.rb.tt +18 -2
  14. data/lib/generators/propel_authentication/templates/test/controllers/auth/lockable_integration_test.rb.tt +1 -1
  15. data/lib/generators/propel_authentication/templates/test/controllers/auth/password_reset_integration_test.rb.tt +8 -8
  16. data/lib/generators/propel_authentication/templates/test/controllers/auth/signup_controller_test.rb.tt +6 -6
  17. data/lib/generators/propel_authentication/templates/test/controllers/auth/tokens_controller_test.rb.tt +1 -1
  18. data/lib/generators/propel_authentication/test/generators/authentication/controllers/tokens_controller_test.rb +1 -1
  19. data/lib/generators/propel_authentication/test/generators/authentication/install_generator_test.rb +1 -1
  20. data/lib/generators/propel_authentication/test/integration/multi_version_generator_test.rb +12 -13
  21. data/lib/propel_authentication.rb +1 -1
  22. metadata +24 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22860db42c802dc6a34029c311149badcf95f0b9c54a2f83767bf4c2f1c62618
4
- data.tar.gz: 30c016587b4500344ad0a6a95feeef37a12cee54a7addd4f912c67fc5b8f4ca3
3
+ metadata.gz: feff8cf5d61966deceb32c0466338c47270c96b06d67304aeeab26304402f83f
4
+ data.tar.gz: 9a5d2b1e807454d4223524dad81b109dd97a655a7ce0512a49c8d22c65c9ddff
5
5
  SHA512:
6
- metadata.gz: 7da4c75f8d12fce6ad7a0686d2ac6fca6146df044e0b8d8bf6f73acb812f851298c270529cb8c9bd6ef10acb992c0a2b62711182ea92caf7deef06bad084d627
7
- data.tar.gz: f94d8b1ec7dfaad482db03aff177dee93af78ef132bd89634af780044f5907f0aa95afe96971540af058f364dfaf4b410f1aaca02311b0b51970b0d83ff6fbf6
6
+ metadata.gz: 18219d594b8084f6dc283d2e5d034413f69492c3ca9861588c40170659586150f118acf23bc9003356144704a4648c84b8265dafbd81e9bad8fc722779b4fd93
7
+ data.tar.gz: 2bcf4ca9a1779fb6487d9e31e28e5035cc71771e1f7983501b1697fd94b78441f849776e76dc73f4c895d84ac739e2bc91c6b0624a06d1ea9b163e4b02c653e2
data/CHANGELOG.md CHANGED
@@ -13,6 +13,25 @@ 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
+
27
+ ## [0.2.1] - 2025-01-14
28
+
29
+ ### Changed
30
+ - **Version synchronization**: Released alongside PropelFacets 0.2.1 and PropelApi 0.2.1
31
+ - Maintains version consistency across the Propel framework ecosystem
32
+ - Ensures compatibility with PropelFacets generator fix for `for_organization` scope
33
+ - No functional changes in this release
34
+
16
35
  ## [0.2.0] - 2025-09-02
17
36
 
18
37
  ### BREAKING CHANGES
@@ -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.7')
120
- add_gem_if_missing('letter_opener', '~> 1.8', group: :development)
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
- meta: {}
268
- settings: {}
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
- meta: {}
277
- settings: {}
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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: :unprocessable_entity
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 :meta, default: {}
10
+ t.jsonb :metadata, default: {}
11
11
  t.jsonb :settings, default: {}
12
12
  else
13
- t.json :meta, default: {}
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 :meta, default: {}
10
+ t.jsonb :metadata, default: {}
9
11
  t.jsonb :settings, default: {}
10
12
  else
11
- t.json :meta, default: {}
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 :meta, default: {}
29
+ t.jsonb :metadata, default: {}
30
30
  t.jsonb :settings, default: {}
31
31
  else
32
- t.json :meta, default: {}
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, fields: [:id, :name]
11
- json_facet :details, fields: [:id, :name, :organization_id, :created_at, :updated_at]
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, fields: [:id, :title]
11
- json_facet :details, fields: [:id, :title, :role, :organization_id, :created_at, :updated_at]
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, fields: [:id, :name, :website, :time_zone]
10
- json_facet :details, fields: [:id, :name, :website, :time_zone, :meta, :settings, :created_at, :updated_at]
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, fields: [:id, :email_address, :username, :phone_number, :first_name, :middle_name, :last_name, :time_zone, :status]
25
- json_facet :details, fields: [:id, :email_address, :username, :phone_number, :first_name, :middle_name, :last_name, :time_zone, :confirmation_sent_at, :unconfirmed_email_address, :confirmed_at, :status, :last_login_at, :failed_login_attempts, :locked_at, :organization_id, :meta, :settings, :created_at, :updated_at], include: [:organization]
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 :unprocessable_entity, "Missing token should return 422"
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 :unprocessable_entity, "Invalid email_address format should be rejected"
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 :unprocessable_entity, "Missing email_address should return validation error"
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 :unprocessable_entity, "Mismatched passwords should be rejected"
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 :unprocessable_entity, "Weak password should be rejected"
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 :unprocessable_entity, "Missing token should be rejected"
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 :unprocessable_entity, "Missing password should be rejected"
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 :unprocessable_entity, "Missing password confirmation should be rejected"
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 :unprocessable_entity, "Missing token should return validation error"
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 :unprocessable_entity
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 :unprocessable_entity
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 :unprocessable_entity
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 :unprocessable_entity
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 :unprocessable_entity
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 :unprocessable_entity
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 :unprocessable_entity, "Missing required parameters should return unprocessable_entity"
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 :unprocessable_entity
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"
@@ -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 :meta, default: {}/, migration)
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 controller structure with proper namespace configuration" do
20
- run_generator ["--namespace=api", "--version=v1"]
19
+ test "generator creates dynamic API versioning structure" do
20
+ run_generator ["--configurable-versioning"]
21
21
 
22
- # Verify direct controllers are created with proper class names (no inheritance)
23
- assert_file "app/controllers/api/v1/tokens_controller.rb" do |content|
24
- assert_match(/class Api::V1::TokensController < ApplicationController/, content)
25
- assert_match(/POST \/api\/v1\/login/, content)
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/v1/passwords_controller.rb" do |content|
33
- assert_match(/class Api::V1::PasswordsController < ApplicationController/, content)
34
- assert_match(/POST \/api\/v1\/reset/, content)
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 with proper namespacing and as: options
40
+ # Verify runtime configurable routes are created
41
41
  assert_file "config/routes.rb" do |content|
42
- assert_match(/namespace :api/, content)
43
- assert_match(/namespace :v1/, content)
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)
@@ -1,3 +1,3 @@
1
1
  module PropelAuthentication
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
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.2.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-02 00:00:00.000000000 Z
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: '2.7'
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: '2.7'
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.