propel_authentication 0.2.1 โ†’ 0.3.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/lib/generators/propel_authentication/install_generator.rb +190 -228
  4. data/lib/generators/propel_authentication/templates/auth/passwords_controller.rb.tt +10 -13
  5. data/lib/generators/propel_authentication/templates/auth/signup_controller.rb.tt +6 -9
  6. data/lib/generators/propel_authentication/templates/auth/tokens_controller.rb.tt +4 -7
  7. data/lib/generators/propel_authentication/templates/core/configuration_methods.rb +38 -1
  8. data/lib/generators/propel_authentication/templates/db/migrate/create_agencies.rb +4 -2
  9. data/lib/generators/propel_authentication/templates/db/migrate/create_agents.rb +6 -1
  10. data/lib/generators/propel_authentication/templates/db/migrate/create_organizations.rb +4 -2
  11. data/lib/generators/propel_authentication/templates/db/migrate/create_users.rb +4 -2
  12. data/lib/generators/propel_authentication/templates/db/propel_seeds.rb.tt +145 -0
  13. data/lib/generators/propel_authentication/templates/doc/signup_flow.md +9 -4
  14. data/lib/generators/propel_authentication/templates/fixtures/agencies.yml.erb +23 -0
  15. data/lib/generators/propel_authentication/templates/fixtures/agents.yml.erb +71 -0
  16. data/lib/generators/propel_authentication/templates/fixtures/invitations.yml.erb +9 -0
  17. data/lib/generators/propel_authentication/templates/fixtures/organizations.yml.erb +21 -0
  18. data/lib/generators/propel_authentication/templates/fixtures/users.yml.erb +77 -0
  19. data/lib/generators/propel_authentication/templates/models/agency.rb.tt +8 -2
  20. data/lib/generators/propel_authentication/templates/models/agent.rb.tt +13 -2
  21. data/lib/generators/propel_authentication/templates/models/invitation.rb.tt +3 -1
  22. data/lib/generators/propel_authentication/templates/models/organization.rb.tt +15 -2
  23. data/lib/generators/propel_authentication/templates/models/user.rb.tt +18 -2
  24. data/lib/generators/propel_authentication/templates/propel_authentication.rb.tt +33 -6
  25. data/lib/generators/propel_authentication/templates/test/controllers/auth/lockable_integration_test.rb.tt +2 -2
  26. data/lib/generators/propel_authentication/templates/test/controllers/auth/password_reset_integration_test.rb.tt +9 -9
  27. data/lib/generators/propel_authentication/templates/test/controllers/auth/signup_controller_test.rb.tt +6 -6
  28. data/lib/generators/propel_authentication/templates/test/controllers/auth/tokens_controller_test.rb.tt +4 -4
  29. data/lib/generators/propel_authentication/test/generators/authentication/controllers/tokens_controller_test.rb +1 -1
  30. data/lib/generators/propel_authentication/test/generators/authentication/install_generator_test.rb +1 -1
  31. data/lib/generators/propel_authentication/test/integration/multi_version_generator_test.rb +12 -13
  32. data/lib/propel_authentication.rb +1 -1
  33. metadata +30 -5
  34. data/lib/generators/propel_authentication/templates/db/seeds.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe981d749ba64d0aa104260e84cc38ed6cb6db9b188d2c93bcb4e3e4d6bed5a1
4
- data.tar.gz: 216d7dfdcf42768a5ec6cc2210d24a4fbda803b80b52ba7a15b2919e735c7cab
3
+ metadata.gz: 2b951cffb4dd4a53fd4f5b16e3f30f97a4fb4e4dae4999f30aeb6ea3ca44bd1f
4
+ data.tar.gz: c8077baca253a2a5ab7770f75043a948adb7fa7e922572c4bd898c0c7fcb979a
5
5
  SHA512:
6
- metadata.gz: f4dc4ca6bccb99b215311666d7d053d06e8450c428ae6b5f60ecaa0b1d93dfc9f9b59c15634804d4cdc7911d0a26adff7ef9780b1569303dbbe2d748a967e35f
7
- data.tar.gz: 28012ada14d8f32e24f4dcde2dc26212a1ab2d838bcfdb5b1ff0ba2c08ee03bbaa499e611b04cdd9b954788ed0477d8d92facfe7fa252ebd759efafc1a5f0230
6
+ metadata.gz: d6996169826450be372a4d8be3c5a5a325bdeb842de547ff8be9a47e3511cec95046a49823964e92b4985da6ef3b0cd1b168dc5c08a9e5865be617168e3f789e
7
+ data.tar.gz: d4417d0632e329aa1ab1bfbd0d865827af970cf7d3a9b598fbbcb4f52f649fc0a6119c94d7a912482b2b9cb2ddb54bb7606d2ec6a8a242e4c400cb4c3f65fb39
data/CHANGELOG.md CHANGED
@@ -13,6 +13,66 @@ 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.1] - 2025-09-11
17
+
18
+ ### ๐Ÿ”ง Installation & Configuration Improvements
19
+ - **Enhanced Install Generator**: Improved handling of noticed gem installation and environment configuration errors
20
+ - Better error detection and handling for missing environment variables
21
+ - Enhanced installation process for the noticed gem integration
22
+ - More robust handling of gem installation edge cases
23
+ - **Fixed duplicate gem insert bug**: Generator now properly checks for existing gem entries before insertion
24
+ - **Improved Seed File Generation**: Enhanced PropelSeeds template with better organization and agent relationships
25
+ - Better seed data structure for multi-tenant scenarios
26
+ - Enhanced fixture and seed file coordination
27
+ - Fixed seed file imports to reflect proper organization tenancy structure
28
+ - **Enhanced Tenancy Configuration System**: Comprehensive improvements to configuration methods and templates
29
+ - Enhanced `PropelAuthentication.configuration` with better tenancy model support
30
+ - Improved configuration methods in core authentication system
31
+ - Better migration templates for agencies, agents, organizations, and users
32
+ - Enhanced model templates with improved association handling
33
+
34
+ ### ๐Ÿ—๏ธ Relationship Model Enhancements
35
+ - **Direct Agent-Organization Relationship**: Added direct relationship between Agent and Organization models
36
+ - Enhanced agency and organization model templates with improved associations
37
+ - Better support for multi-tenant organizational structures
38
+ - Improved migration templates to support direct agent-organization relationships
39
+ - **Enhanced User Model Relationships**: Improved user model template with better agency and organization associations
40
+ - Enhanced model relationships for cleaner multi-tenant access patterns
41
+ - Better integration with PropelApi polymorphic support
42
+
43
+ ### ๐Ÿงช Testing & Fixtures Improvements
44
+ - **Enhanced Fixture Templates**: Improved fixture generation with ERB templates for agencies, agents, organizations, users, and invitations
45
+ - Better fixture data coordination across authentication models
46
+ - Enhanced test setup with realistic fixture relationships
47
+ - Improved fixture template adoption for better integration with PropelApi generators
48
+ - **Test Template Updates**: Enhanced authentication test templates for better integration
49
+ - Improved lockable integration test templates
50
+ - Enhanced password reset integration test templates
51
+ - Better token controller test templates with improved authentication flows
52
+
53
+ ### ๐Ÿ› ๏ธ Generator & Template System
54
+ - **Controller Template Enhancements**: Comprehensive improvements to authentication controller templates
55
+ - Enhanced signup controller template with better organization and agency handling
56
+ - Improved passwords controller template for better error handling
57
+ - Updated tokens controller template with enhanced authentication flows
58
+ - Better integration with full-stack and API-only Rails application architectures
59
+ - **Configuration Method Improvements**: Enhanced core configuration methods for better tenancy support
60
+ - **Migration Template Improvements**: Enhanced migration templates for agencies, agents, and users with better relationship support
61
+ - Improved create_agencies migration template
62
+ - Enhanced create_agents migration with better relationship handling
63
+ - Updated create_users migration for improved multi-tenancy support
64
+
65
+ ## [0.3.0] - 2025-01-15
66
+
67
+ ### ๐Ÿ”ง Compatibility Updates
68
+ - **PropelApi Integration**: Updated to work seamlessly with PropelApi 0.3.0's new polymorphic association features
69
+ - **Test Template Compatibility**: Authentication templates now compatible with enhanced polymorphic test generation
70
+ - **Dependency Updates**: Bumped version to maintain compatibility with PropelApi 0.3.0
71
+
72
+ ### ๐Ÿ› Bug Fixes
73
+ - **Generator Compatibility**: Fixed potential conflicts with PropelApi's enhanced generator argument processing
74
+ - **Template Consistency**: Ensured all authentication templates follow the same patterns as PropelApi 0.3.0
75
+
16
76
  ## [0.2.1] - 2025-01-14
17
77
 
18
78
  ### Changed
@@ -33,6 +33,30 @@ module PropelAuthentication
33
33
 
34
34
  desc "Generate JWT-based authentication system with configurable URL architecture"
35
35
 
36
+ class_option :namespace,
37
+ type: :string,
38
+ desc: "API namespace (e.g., api)"
39
+
40
+ class_option :version,
41
+ type: :string,
42
+ desc: "API version (e.g., v1)"
43
+
44
+ class_option :auth_scope,
45
+ type: :string,
46
+ desc: "Authentication scope (e.g., auth for /api/v1/auth/login)"
47
+
48
+ class_option :tenancy_enabled,
49
+ type: :boolean,
50
+ desc: "Enable multi-tenancy system (master switch)"
51
+
52
+ class_option :organization_required,
53
+ type: :boolean,
54
+ desc: "Require users to belong to organizations"
55
+
56
+ class_option :agency_required,
57
+ type: :boolean,
58
+ desc: "Enable agency tenancy within organizations"
59
+
36
60
  def copy_jwt_initializer
37
61
  determine_configuration
38
62
 
@@ -43,6 +67,9 @@ module PropelAuthentication
43
67
  # Convert to ERB template to support configuration
44
68
  template "propel_authentication.rb.tt", "config/initializers/propel_authentication.rb"
45
69
  say "Created PropelAuthentication configuration with namespace: #{namespace_display}, version: #{version_display}", :green
70
+
71
+ # Load the configuration immediately so templates can access it
72
+ load_propel_authentication_configuration
46
73
  end
47
74
  end
48
75
 
@@ -50,11 +77,11 @@ module PropelAuthentication
50
77
  # Detect rendering engine for conditional facet generation
51
78
  @rendering_engine = detect_rendering_engine
52
79
 
53
- template "models/user.rb.tt", "app/models/user.rb"
54
- template "models/organization.rb.tt", "app/models/organization.rb"
55
- template "models/agency.rb.tt", "app/models/agency.rb"
56
- template "models/agent.rb.tt", "app/models/agent.rb"
57
- template "models/invitation.rb.tt", "app/models/invitation.rb"
80
+ copy_users_model
81
+ copy_invitations_model
82
+ copy_organizations_model if organization_required?
83
+ copy_agencies_model if agency_required?
84
+ copy_agents_model if agency_required?
58
85
  end
59
86
 
60
87
  def copy_authentication_concerns
@@ -106,18 +133,37 @@ module PropelAuthentication
106
133
  template "test/controllers/auth/password_reset_integration_test.rb.tt", "test/controllers/auth/password_reset_integration_test.rb"
107
134
  end
108
135
 
109
- def copy_test_fixtures
110
- create_file "test/fixtures/organizations.yml", organizations_fixture
111
- create_file "test/fixtures/users.yml", users_fixture
112
- create_file "test/fixtures/agencies.yml", agencies_fixture
113
- create_file "test/fixtures/agents.yml", agents_fixture
114
- create_file "test/fixtures/invitations.yml", invitations_fixture
115
- end
116
136
 
117
137
  def add_authentication_gems
118
138
  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)
139
+ add_gem_if_missing('jwt', '~> 3.1.2')
140
+ add_gem_if_missing('noticed', '~> 2.8.1')
141
+ add_gem_if_missing('letter_opener', '~> 1.10', group: :development)
142
+
143
+ say "๐Ÿ“ฆ Installing gems...", :blue
144
+ run "bundle install"
145
+
146
+ # Require bcrypt so it's available for fixture templates
147
+ begin
148
+ require 'bcrypt'
149
+ rescue LoadError
150
+ say "โš ๏ธ BCrypt not yet available, fixtures may need manual adjustment", :yellow
151
+ end
152
+ end
153
+
154
+ def install_noticed_gem
155
+ say ""
156
+ say "๐Ÿ“ฆ Setting up Noticed gem for email notifications...", :green
157
+
158
+ begin
159
+ # Run the noticed install generator
160
+ rails_command "noticed:install:migrations", capture: true
161
+ say "โœ… Noticed gem configured successfully", :green
162
+ rescue => e
163
+ say "โš ๏ธ Warning: Could not run noticed:install:migrations automatically", :yellow
164
+ say " Please run manually: rails generate noticed:install", :yellow
165
+ say " Error: #{e.message}", :red if options[:verbose]
166
+ end
121
167
  end
122
168
 
123
169
  def add_authentication_routes
@@ -136,16 +182,25 @@ module PropelAuthentication
136
182
  route template_file_for_routes
137
183
  end
138
184
 
139
- def copy_authentication_migrations
140
- %w[organizations users agencies agents invitations].each do |table|
141
- unless migration_exists?("create_#{table}")
142
- migration_template "db/migrate/create_#{table}.rb", "db/migrate/create_#{table}.rb"
143
- end
144
- end
185
+ def copy_authentication_migrations_and_fixtures
186
+ copy_users_migration_and_fixtures
187
+ copy_invitations_migration_and_fixtures
188
+ copy_organizations_migration_and_fixtures if organization_required?
189
+ copy_agencies_migration_and_fixtures if agency_required?
190
+ copy_agents_migration_and_fixtures if agency_required?
145
191
  end
146
192
 
147
193
  def copy_database_seeds
148
- copy_file "db/seeds.rb", "db/seeds.rb"
194
+ template "db/propel_seeds.rb.tt", "db/propel_seeds.rb"
195
+
196
+ # Add require_relative to main seeds.rb file so propel_seeds is loaded during rails db:seed
197
+ seeds_file = File.join(destination_root, "db/seeds.rb")
198
+ if File.exist?(seeds_file)
199
+ seeds_content = File.read(seeds_file)
200
+ unless seeds_content.include?("require_relative 'propel_seeds'")
201
+ append_to_file "db/seeds.rb", "\n# Load Propel Authentication seed data\nrequire_relative 'propel_seeds'\n"
202
+ end
203
+ end
149
204
  end
150
205
 
151
206
  def extract_generator_for_customization
@@ -197,6 +252,18 @@ module PropelAuthentication
197
252
 
198
253
  private
199
254
 
255
+ def load_propel_authentication_configuration
256
+ # Load the configuration file we just created so templates can access it
257
+ config_file = File.join(destination_root, "config/initializers/propel_authentication.rb")
258
+ if File.exist?(config_file)
259
+ begin
260
+ load config_file
261
+ rescue => e
262
+ say "Warning: Could not load PropelAuthentication configuration: #{e.message}", :yellow
263
+ end
264
+ end
265
+ end
266
+
200
267
  # Check if authentication routes already exist in routes file
201
268
  def authentication_routes_exist?(routes_content)
202
269
  # Check for key authentication routes based on our configuration
@@ -227,218 +294,11 @@ module PropelAuthentication
227
294
  ERB.new(File.read(source_path), trim_mode: '-').result(binding)
228
295
  end
229
296
 
230
- def add_gem_if_missing(gem_name, version_requirement = nil, options = {})
231
- gemfile_path = File.join(destination_root, 'Gemfile')
232
- return unless File.exist?(gemfile_path)
233
-
234
- gemfile_content = File.read(gemfile_path)
235
-
236
- # Check if gem is already present (handles various quote styles and spacing)
237
- gem_pattern = /gem\s+['"]#{Regexp.escape(gem_name)}['"](?:\s*,\s*['"][^'"]*['"])?/
238
-
239
- if gemfile_content.match?(gem_pattern)
240
- say_status :exists, "gem '#{gem_name}' already in Gemfile", :blue
241
- return
242
- end
243
-
244
- # Add the gem using Rails' built-in method
245
- if version_requirement && options.any?
246
- gem gem_name, version_requirement, options
247
- elsif version_requirement
248
- gem gem_name, version_requirement
249
- else
250
- gem gem_name
251
- end
252
-
253
- say_status :gemfile, "gem '#{gem_name}' #{version_requirement}", :green
254
- end
255
297
 
256
298
  def migration_exists?(migration_name)
257
299
  Dir.glob("#{destination_root}/db/migrate/*_#{migration_name}.rb").any?
258
300
  end
259
301
 
260
- # Fixture content methods
261
- def organizations_fixture
262
- <<~FIXTURE
263
- acme_org:
264
- name: "Acme Corporation"
265
- website: "https://acme-corp.com"
266
- time_zone: "UTC"
267
- meta: {}
268
- settings: {}
269
- created_at: <%= 30.days.ago %>
270
- updated_at: <%= 1.day.ago %>
271
-
272
- tech_startup:
273
- name: "Tech Startup Inc"
274
- website: "https://techstartup.io"
275
- time_zone: "America/New_York"
276
- meta: {}
277
- settings: {}
278
- created_at: <%= 15.days.ago %>
279
- updated_at: <%= 2.days.ago %>
280
- FIXTURE
281
- end
282
-
283
- def users_fixture
284
- <<~FIXTURE
285
- john_user:
286
- email_address: "john@example.com"
287
- username: "john_doe"
288
- first_name: "John"
289
- last_name: "Doe"
290
- password_digest: "<%= BCrypt::Password.create('password123') %>"
291
- organization: acme_org
292
- status: "active"
293
- confirmed_at: null
294
- confirmation_token: "<%= SecureRandom.hex(32) %>"
295
- confirmation_sent_at: <%= 1.hour.ago %>
296
- created_at: <%= 7.days.ago %>
297
- updated_at: <%= 1.day.ago %>
298
-
299
- jane_user:
300
- email_address: "jane@example.com"
301
- username: "jane_smith"
302
- first_name: "Jane"
303
- last_name: "Smith"
304
- password_digest: "<%= BCrypt::Password.create('password123') %>"
305
- organization: tech_startup
306
- status: "active"
307
- confirmed_at: null
308
- failed_login_attempts: 0
309
- locked_at: null
310
- created_at: <%= 5.days.ago %>
311
- updated_at: <%= 1.day.ago %>
312
-
313
- confirmed_user:
314
- email_address: "confirmed@example.com"
315
- username: "confirmed_user"
316
- first_name: "Confirmed"
317
- last_name: "User"
318
- password_digest: "<%= BCrypt::Password.create('password123') %>"
319
- organization: acme_org
320
- status: "active"
321
- confirmed_at: <%= 7.days.ago %>
322
- created_at: <%= 14.days.ago %>
323
- updated_at: <%= 1.day.ago %>
324
-
325
- locked_user:
326
- email_address: "locked@example.com"
327
- username: "locked_user"
328
- first_name: "Locked"
329
- last_name: "User"
330
- password_digest: "<%= BCrypt::Password.create('password123') %>"
331
- organization: acme_org
332
- status: "active"
333
- confirmed_at: <%= 10.days.ago %>
334
- failed_login_attempts: 5
335
- locked_at: <%= 1.hour.ago %>
336
- created_at: <%= 20.days.ago %>
337
- updated_at: <%= 1.hour.ago %>
338
-
339
- expired_confirmation_user:
340
- email_address: "expired@example.com"
341
- username: "expired_user"
342
- first_name: "Expired"
343
- last_name: "User"
344
- password_digest: "<%= BCrypt::Password.create('password123') %>"
345
- organization: tech_startup
346
- status: "active"
347
- confirmed_at: null
348
- confirmation_token: "<%= SecureRandom.hex(32) %>"
349
- confirmation_sent_at: <%= 25.hours.ago %>
350
- created_at: <%= 30.days.ago %>
351
- updated_at: <%= 25.hours.ago %>
352
- FIXTURE
353
- end
354
-
355
- def agencies_fixture
356
- <<~FIXTURE
357
- marketing_agency:
358
- name: "Marketing Solutions"
359
- organization: acme_org
360
- created_at: <%= 10.days.ago %>
361
- updated_at: <%= 2.days.ago %>
362
-
363
- sales_agency:
364
- name: "Sales Department"
365
- organization: acme_org
366
- created_at: <%= 9.days.ago %>
367
- updated_at: <%= 2.days.ago %>
368
-
369
- tech_agency:
370
- name: "Tech Solutions"
371
- organization: tech_startup
372
- created_at: <%= 8.days.ago %>
373
- updated_at: <%= 1.day.ago %>
374
-
375
- support_agency:
376
- name: "Support Team"
377
- organization: tech_startup
378
- created_at: <%= 7.days.ago %>
379
- updated_at: <%= 1.day.ago %>
380
- FIXTURE
381
- end
382
-
383
- def agents_fixture
384
- <<~FIXTURE
385
- john_marketing_agent:
386
- user: john_user
387
- agency: marketing_agency
388
- role: "manager"
389
- created_at: <%= 8.days.ago %>
390
- updated_at: <%= 1.day.ago %>
391
-
392
- confirmed_sales_agent:
393
- user: confirmed_user
394
- agency: sales_agency
395
- role: "analyst"
396
- created_at: <%= 7.days.ago %>
397
- updated_at: <%= 1.day.ago %>
398
-
399
- locked_marketing_agent:
400
- user: locked_user
401
- agency: marketing_agency
402
- role: "coordinator"
403
- created_at: <%= 6.days.ago %>
404
- updated_at: <%= 1.day.ago %>
405
-
406
- jane_tech_agent:
407
- user: jane_user
408
- agency: tech_agency
409
- role: "developer"
410
- created_at: <%= 5.days.ago %>
411
- updated_at: <%= 1.day.ago %>
412
-
413
- expired_support_agent:
414
- user: expired_confirmation_user
415
- agency: support_agency
416
- role: "specialist"
417
- created_at: <%= 4.days.ago %>
418
- updated_at: <%= 1.day.ago %>
419
-
420
- locked_sales_agent:
421
- user: locked_user
422
- agency: sales_agency
423
- role: "trainee"
424
- created_at: <%= 3.days.ago %>
425
- updated_at: <%= 1.day.ago %>
426
- FIXTURE
427
- end
428
-
429
- def invitations_fixture
430
- <<~FIXTURE
431
- pending_invitation:
432
- email_address: "newuser@example.com"
433
- first_name: "New"
434
- last_name: "User"
435
- organization: acme_org
436
- inviter: john_user
437
- status: "pending"
438
- created_at: <%= 3.days.ago %>
439
- updated_at: <%= 3.days.ago %>
440
- FIXTURE
441
- end
442
302
 
443
303
  def detect_rendering_engine
444
304
  # Check for common rendering engines in order of preference
@@ -460,5 +320,107 @@ module PropelAuthentication
460
320
  rescue
461
321
  false
462
322
  end
323
+
324
+ private
325
+
326
+ # Individual model methods
327
+ def copy_users_model
328
+ template "models/user.rb.tt", "app/models/user.rb"
329
+ end
330
+
331
+ def copy_organizations_model
332
+ template "models/organization.rb.tt", "app/models/organization.rb"
333
+ end
334
+
335
+ def copy_agencies_model
336
+ template "models/agency.rb.tt", "app/models/agency.rb"
337
+ end
338
+
339
+ def copy_agents_model
340
+ template "models/agent.rb.tt", "app/models/agent.rb"
341
+ end
342
+
343
+ def copy_invitations_model
344
+ template "models/invitation.rb.tt", "app/models/invitation.rb"
345
+ end
346
+
347
+ # Combined migration and fixture methods
348
+ def copy_users_migration_and_fixtures
349
+ migration_template "db/migrate/create_users.rb", "db/migrate/create_users.rb" unless migration_exists?("create_users")
350
+ template "fixtures/users.yml.erb", "test/fixtures/users.yml"
351
+ end
352
+
353
+ def copy_organizations_migration_and_fixtures
354
+ migration_template "db/migrate/create_organizations.rb", "db/migrate/create_organizations.rb" unless migration_exists?("create_organizations")
355
+ template "fixtures/organizations.yml.erb", "test/fixtures/organizations.yml"
356
+ end
357
+
358
+ def copy_agencies_migration_and_fixtures
359
+ migration_template "db/migrate/create_agencies.rb", "db/migrate/create_agencies.rb" unless migration_exists?("create_agencies")
360
+ template "fixtures/agencies.yml.erb", "test/fixtures/agencies.yml"
361
+ end
362
+
363
+ def copy_agents_migration_and_fixtures
364
+ migration_template "db/migrate/create_agents.rb", "db/migrate/create_agents.rb" unless migration_exists?("create_agents")
365
+ template "fixtures/agents.yml.erb", "test/fixtures/agents.yml"
366
+ end
367
+
368
+ def copy_invitations_migration_and_fixtures
369
+ migration_template "db/migrate/create_invitations.rb", "db/migrate/create_invitations.rb" unless migration_exists?("create_invitations")
370
+ template "fixtures/invitations.yml.erb", "test/fixtures/invitations.yml"
371
+ end
372
+
373
+ # Configuration helper methods
374
+ def organization_required?
375
+ return true unless configuration_loaded?
376
+ PropelAuthentication.configuration.organization_required?
377
+ rescue
378
+ true # Default to full tenancy if config unavailable
379
+ end
380
+
381
+ def agency_required?
382
+ return true unless configuration_loaded?
383
+ PropelAuthentication.configuration.agency_required?
384
+ rescue
385
+ true # Default to full tenancy if config unavailable
386
+ end
387
+
388
+ def configuration_loaded?
389
+ defined?(PropelAuthentication) &&
390
+ PropelAuthentication.respond_to?(:configuration) &&
391
+ PropelAuthentication.configuration.present?
392
+ rescue
393
+ false
394
+ end
395
+
396
+ def add_gem_if_missing(gem_name, version_requirement = nil, options = {})
397
+ gemfile_path = File.join(destination_root, 'Gemfile')
398
+ return unless File.exist?(gemfile_path)
399
+
400
+ gemfile_content = File.read(gemfile_path)
401
+
402
+ # Check if gem is already present and not commented out
403
+ gem_pattern = /^\s*gem\s+['"]#{Regexp.escape(gem_name)}['"](?:\s*,\s*['"][^'"]*['"])?/
404
+ commented_gem_pattern = /^\s*#.*gem\s+['"]#{Regexp.escape(gem_name)}['"]/
405
+
406
+ # Check each line to see if the gem exists and is not commented out
407
+ gem_exists = gemfile_content.lines.any? do |line|
408
+ line.match?(gem_pattern) && !line.match?(commented_gem_pattern)
409
+ end
410
+
411
+ if gem_exists
412
+ say_status :exists, "gem '#{gem_name}' already in Gemfile", :blue
413
+ return
414
+ end
415
+
416
+ # Use Rails built-in gem method to add it
417
+ if options[:group]
418
+ gem gem_name, version_requirement, group: options[:group]
419
+ else
420
+ gem gem_name, version_requirement
421
+ end
422
+
423
+ say_status :gemfile, "gem '#{gem_name}' #{version_requirement}", :green
424
+ end
463
425
  end
464
426
  end
@@ -1,7 +1,4 @@
1
- class <%= auth_controller_class_name('passwords') %> < ApplicationController
2
- <%- unless api_only_app? -%>
3
- include RackSessionDisable
4
- <%- end -%>
1
+ class <%= auth_controller_class_name('passwords') %> < Api::BaseController
5
2
  include PropelAuthenticationConcern
6
3
 
7
4
  # POST <%= auth_route_prefix %>/reset
@@ -10,12 +7,12 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
10
7
 
11
8
  # Validate email_address parameter
12
9
  if email_address.blank?
13
- return render json: { error: "Email address is required" }, status: :unprocessable_entity
10
+ return render json: { error: "Email address is required" }, status: :unprocessable_content
14
11
  end
15
12
 
16
13
  # Validate email format
17
14
  unless email_address.match?(URI::MailTo::EMAIL_REGEXP)
18
- return render json: { error: "Email address format is invalid" }, status: :unprocessable_entity
15
+ return render json: { error: "Email address format is invalid" }, status: :unprocessable_content
19
16
  end
20
17
 
21
18
  user = User.find_by(email_address: email_address)
@@ -46,7 +43,7 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
46
43
  end
47
44
  rescue => e
48
45
  Rails.logger.error "Password reset creation error: #{e.message}"
49
- render json: { error: "Unable to process password reset request" }, status: :unprocessable_entity
46
+ render json: { error: "Unable to process password reset request" }, status: :unprocessable_content
50
47
  end
51
48
 
52
49
  # GET <%= auth_route_prefix %>/reset
@@ -54,7 +51,7 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
54
51
  token = params[:token]
55
52
 
56
53
  if token.blank?
57
- render json: { error: 'Reset token is required' }, status: :unprocessable_entity
54
+ render json: { error: 'Reset token is required' }, status: :unprocessable_content
58
55
  return
59
56
  end
60
57
 
@@ -89,15 +86,15 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
89
86
 
90
87
  # Validate required parameters
91
88
  if token.blank?
92
- return render json: { error: 'Reset token is required' }, status: :unprocessable_entity
89
+ return render json: { error: 'Reset token is required' }, status: :unprocessable_content
93
90
  end
94
91
 
95
92
  if new_password.blank?
96
- return render json: { error: 'New password is required' }, status: :unprocessable_entity
93
+ return render json: { error: 'New password is required' }, status: :unprocessable_content
97
94
  end
98
95
 
99
96
  if new_password != password_confirmation
100
- return render json: { error: 'Password confirmation does not match password' }, status: :unprocessable_entity
97
+ return render json: { error: 'Password confirmation does not match password' }, status: :unprocessable_content
101
98
  end
102
99
 
103
100
  user = User.find_by_jwt_password_reset_token(token)
@@ -123,10 +120,10 @@ class <%= auth_controller_class_name('passwords') %> < ApplicationController
123
120
  render json: {
124
121
  error: primary_error, # Use specific validation message
125
122
  details: error_messages
126
- }, status: :unprocessable_entity
123
+ }, status: :unprocessable_content
127
124
  end
128
125
  rescue => e
129
126
  Rails.logger.error "Password reset update error: #{e.message}"
130
- render json: { error: 'Unable to reset password' }, status: :unprocessable_entity
127
+ render json: { error: 'Unable to reset password' }, status: :unprocessable_content
131
128
  end
132
129
  end
@@ -1,8 +1,4 @@
1
- class <%= auth_controller_class_name('signup') %> < ApplicationController
2
- <%- unless api_only_app? -%>
3
- include RackSessionDisable
4
- <%- end -%>
5
-
1
+ class <%= auth_controller_class_name('signup') %> < Api::BaseController
6
2
  # POST <%= auth_route_prefix %>/signup
7
3
  def create
8
4
  # Validate agency requirements if agency tenancy is enabled
@@ -19,6 +15,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
19
15
  # Create agent relationship so user has immediate agency access
20
16
  @user.agents.create!(
21
17
  agency: @agency,
18
+ organization: @organization,
22
19
  role: agent_role_param
23
20
  )
24
21
  end
@@ -41,7 +38,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
41
38
  error: 'Validation failed',
42
39
  details: extract_validation_errors(e),
43
40
  message: 'Please correct the errors and try again'
44
- }, status: :unprocessable_entity
41
+ }, status: :unprocessable_content
45
42
  rescue => e
46
43
  render json: {
47
44
  error: 'Account creation failed',
@@ -187,7 +184,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
187
184
  def agency_tenancy_enabled?
188
185
  # Check PropelAuthentication configuration (owns tenancy models)
189
186
  if defined?(PropelAuthentication) && PropelAuthentication.respond_to?(:configuration)
190
- PropelAuthentication.configuration.agency_tenancy
187
+ PropelAuthentication.configuration.agency_required?
191
188
  else
192
189
  true # Safe default - enables agency tenancy when configuration unavailable
193
190
  end
@@ -224,7 +221,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
224
221
  message: 'Agency details must be provided when agency tenancy is enabled',
225
222
  code: 'MISSING_AGENCY_DATA',
226
223
  hint: 'Include an "agency" object with name and other details in your request'
227
- }, status: :unprocessable_entity
224
+ }, status: :unprocessable_content
228
225
  return false
229
226
  end
230
227
 
@@ -233,7 +230,7 @@ class <%= auth_controller_class_name('signup') %> < ApplicationController
233
230
  error: 'Agency name required',
234
231
  message: 'Agency name is required when creating an agency',
235
232
  code: 'MISSING_AGENCY_NAME'
236
- }, status: :unprocessable_entity
233
+ }, status: :unprocessable_content
237
234
  return false
238
235
  end
239
236