propel_authentication 0.3.0 โ†’ 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 (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/lib/generators/propel_authentication/install_generator.rb +188 -240
  4. data/lib/generators/propel_authentication/templates/auth/passwords_controller.rb.tt +1 -4
  5. data/lib/generators/propel_authentication/templates/auth/signup_controller.rb.tt +3 -6
  6. data/lib/generators/propel_authentication/templates/auth/tokens_controller.rb.tt +2 -5
  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 +2 -0
  9. data/lib/generators/propel_authentication/templates/db/migrate/create_agents.rb +6 -1
  10. data/lib/generators/propel_authentication/templates/db/migrate/create_users.rb +2 -0
  11. data/lib/generators/propel_authentication/templates/db/propel_seeds.rb.tt +145 -0
  12. data/lib/generators/propel_authentication/templates/doc/signup_flow.md +9 -4
  13. data/lib/generators/propel_authentication/templates/fixtures/agencies.yml.erb +23 -0
  14. data/lib/generators/propel_authentication/templates/fixtures/agents.yml.erb +71 -0
  15. data/lib/generators/propel_authentication/templates/fixtures/invitations.yml.erb +9 -0
  16. data/lib/generators/propel_authentication/templates/fixtures/organizations.yml.erb +21 -0
  17. data/lib/generators/propel_authentication/templates/fixtures/users.yml.erb +77 -0
  18. data/lib/generators/propel_authentication/templates/models/agency.rb.tt +4 -0
  19. data/lib/generators/propel_authentication/templates/models/agent.rb.tt +9 -0
  20. data/lib/generators/propel_authentication/templates/models/invitation.rb.tt +3 -1
  21. data/lib/generators/propel_authentication/templates/models/organization.rb.tt +3 -0
  22. data/lib/generators/propel_authentication/templates/propel_authentication.rb.tt +33 -6
  23. data/lib/generators/propel_authentication/templates/test/controllers/auth/lockable_integration_test.rb.tt +1 -1
  24. data/lib/generators/propel_authentication/templates/test/controllers/auth/password_reset_integration_test.rb.tt +1 -1
  25. data/lib/generators/propel_authentication/templates/test/controllers/auth/tokens_controller_test.rb.tt +4 -4
  26. data/lib/propel_authentication.rb +1 -1
  27. metadata +8 -3
  28. 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: feff8cf5d61966deceb32c0466338c47270c96b06d67304aeeab26304402f83f
4
- data.tar.gz: 9a5d2b1e807454d4223524dad81b109dd97a655a7ce0512a49c8d22c65c9ddff
3
+ metadata.gz: 2b951cffb4dd4a53fd4f5b16e3f30f97a4fb4e4dae4999f30aeb6ea3ca44bd1f
4
+ data.tar.gz: c8077baca253a2a5ab7770f75043a948adb7fa7e922572c4bd898c0c7fcb979a
5
5
  SHA512:
6
- metadata.gz: 18219d594b8084f6dc283d2e5d034413f69492c3ca9861588c40170659586150f118acf23bc9003356144704a4648c84b8265dafbd81e9bad8fc722779b4fd93
7
- data.tar.gz: 2bcf4ca9a1779fb6487d9e31e28e5035cc71771e1f7983501b1697fd94b78441f849776e76dc73f4c895d84ac739e2bc91c6b0624a06d1ea9b163e4b02c653e2
6
+ metadata.gz: d6996169826450be372a4d8be3c5a5a325bdeb842de547ff8be9a47e3511cec95046a49823964e92b4985da6ef3b0cd1b168dc5c08a9e5865be617168e3f789e
7
+ data.tar.gz: d4417d0632e329aa1ab1bfbd0d865827af970cf7d3a9b598fbbcb4f52f649fc0a6119c94d7a912482b2b9cb2ddb54bb7606d2ec6a8a242e4c400cb4c3f65fb39
data/CHANGELOG.md CHANGED
@@ -13,6 +13,55 @@ 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
+
16
65
  ## [0.3.0] - 2025-01-15
17
66
 
18
67
  ### ๐Ÿ”ง Compatibility Updates
@@ -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
139
  add_gem_if_missing('jwt', '~> 3.1.2')
140
+ add_gem_if_missing('noticed', '~> 2.8.1')
120
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,232 +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
- 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" }
271
- created_at: <%= 30.days.ago %>
272
- updated_at: <%= 1.day.ago %>
273
-
274
- tech_startup:
275
- name: "Tech Startup Inc"
276
- website: "https://techstartup.io"
277
- time_zone: "America/New_York"
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" }
282
- created_at: <%= 15.days.ago %>
283
- updated_at: <%= 2.days.ago %>
284
- FIXTURE
285
- end
286
-
287
- def users_fixture
288
- <<~FIXTURE
289
- john_user:
290
- email_address: "john@example.com"
291
- username: "john_doe"
292
- first_name: "John"
293
- last_name: "Doe"
294
- password_digest: "<%= BCrypt::Password.create('password123') %>"
295
- organization: acme_org
296
- status: "active"
297
- confirmed_at: null
298
- confirmation_token: "<%= SecureRandom.hex(32) %>"
299
- confirmation_sent_at: <%= 1.hour.ago %>
300
- metadata: { user_type: "admin", department: "engineering", priority: "high" }
301
- settings: { theme: "dark", language: "en", notifications: true }
302
- created_at: <%= 7.days.ago %>
303
- updated_at: <%= 1.day.ago %>
304
-
305
- jane_user:
306
- email_address: "jane@example.com"
307
- username: "jane_smith"
308
- first_name: "Jane"
309
- last_name: "Smith"
310
- password_digest: "<%= BCrypt::Password.create('password123') %>"
311
- organization: tech_startup
312
- status: "active"
313
- confirmed_at: null
314
- failed_login_attempts: 0
315
- locked_at: null
316
- metadata: { user_type: "manager", department: "marketing", priority: "high" }
317
- settings: { theme: "light", language: "en", notifications: false }
318
- created_at: <%= 5.days.ago %>
319
- updated_at: <%= 1.day.ago %>
320
-
321
- confirmed_user:
322
- email_address: "confirmed@example.com"
323
- username: "confirmed_user"
324
- first_name: "Confirmed"
325
- last_name: "User"
326
- password_digest: "<%= BCrypt::Password.create('password123') %>"
327
- organization: acme_org
328
- status: "active"
329
- confirmed_at: <%= 7.days.ago %>
330
- metadata: { user_type: "employee", department: "sales", priority: "medium" }
331
- settings: { theme: "auto", language: "es", notifications: true }
332
- created_at: <%= 14.days.ago %>
333
- updated_at: <%= 1.day.ago %>
334
-
335
- locked_user:
336
- email_address: "locked@example.com"
337
- username: "locked_user"
338
- first_name: "Locked"
339
- last_name: "User"
340
- password_digest: "<%= BCrypt::Password.create('password123') %>"
341
- organization: acme_org
342
- status: "active"
343
- confirmed_at: <%= 10.days.ago %>
344
- failed_login_attempts: 5
345
- locked_at: <%= 1.hour.ago %>
346
- metadata: { user_type: "employee", department: "support", priority: "low" }
347
- settings: { theme: "light", language: "en", notifications: false }
348
- created_at: <%= 20.days.ago %>
349
- updated_at: <%= 1.hour.ago %>
350
-
351
- expired_confirmation_user:
352
- email_address: "expired@example.com"
353
- username: "expired_user"
354
- first_name: "Expired"
355
- last_name: "User"
356
- password_digest: "<%= BCrypt::Password.create('password123') %>"
357
- organization: tech_startup
358
- status: "active"
359
- confirmed_at: null
360
- confirmation_token: "<%= SecureRandom.hex(32) %>"
361
- confirmation_sent_at: <%= 25.hours.ago %>
362
- metadata: { user_type: "test", department: "qa", priority: "low" }
363
- settings: { theme: "dark", language: "fr", notifications: false }
364
- created_at: <%= 30.days.ago %>
365
- updated_at: <%= 25.hours.ago %>
366
- FIXTURE
367
- end
368
-
369
- def agencies_fixture
370
- <<~FIXTURE
371
- marketing_agency:
372
- name: "Marketing Solutions"
373
- organization: acme_org
374
- created_at: <%= 10.days.ago %>
375
- updated_at: <%= 2.days.ago %>
376
-
377
- sales_agency:
378
- name: "Sales Department"
379
- organization: acme_org
380
- created_at: <%= 9.days.ago %>
381
- updated_at: <%= 2.days.ago %>
382
-
383
- tech_agency:
384
- name: "Tech Solutions"
385
- organization: tech_startup
386
- created_at: <%= 8.days.ago %>
387
- updated_at: <%= 1.day.ago %>
388
-
389
- support_agency:
390
- name: "Support Team"
391
- organization: tech_startup
392
- created_at: <%= 7.days.ago %>
393
- updated_at: <%= 1.day.ago %>
394
- FIXTURE
395
- end
396
-
397
- def agents_fixture
398
- <<~FIXTURE
399
- john_marketing_agent:
400
- user: john_user
401
- agency: marketing_agency
402
- role: "manager"
403
- created_at: <%= 8.days.ago %>
404
- updated_at: <%= 1.day.ago %>
405
-
406
- confirmed_sales_agent:
407
- user: confirmed_user
408
- agency: sales_agency
409
- role: "analyst"
410
- created_at: <%= 7.days.ago %>
411
- updated_at: <%= 1.day.ago %>
412
-
413
- locked_marketing_agent:
414
- user: locked_user
415
- agency: marketing_agency
416
- role: "coordinator"
417
- created_at: <%= 6.days.ago %>
418
- updated_at: <%= 1.day.ago %>
419
-
420
- jane_tech_agent:
421
- user: jane_user
422
- agency: tech_agency
423
- role: "developer"
424
- created_at: <%= 5.days.ago %>
425
- updated_at: <%= 1.day.ago %>
426
-
427
- expired_support_agent:
428
- user: expired_confirmation_user
429
- agency: support_agency
430
- role: "specialist"
431
- created_at: <%= 4.days.ago %>
432
- updated_at: <%= 1.day.ago %>
433
-
434
- locked_sales_agent:
435
- user: locked_user
436
- agency: sales_agency
437
- role: "trainee"
438
- created_at: <%= 3.days.ago %>
439
- updated_at: <%= 1.day.ago %>
440
- FIXTURE
441
- end
442
-
443
- def invitations_fixture
444
- <<~FIXTURE
445
- pending_invitation:
446
- email_address: "newuser@example.com"
447
- first_name: "New"
448
- last_name: "User"
449
- organization: acme_org
450
- inviter: john_user
451
- status: "pending"
452
- created_at: <%= 3.days.ago %>
453
- updated_at: <%= 3.days.ago %>
454
- FIXTURE
455
- end
456
302
 
457
303
  def detect_rendering_engine
458
304
  # Check for common rendering engines in order of preference
@@ -474,5 +320,107 @@ module PropelAuthentication
474
320
  rescue
475
321
  false
476
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
477
425
  end
478
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
@@ -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
@@ -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
@@ -1,7 +1,4 @@
1
- class <%= auth_controller_class_name('tokens') %> < ApplicationController
2
- <%- unless api_only_app? -%>
3
- include RackSessionDisable
4
- <%- end -%>
1
+ class <%= auth_controller_class_name('tokens') %> < Api::BaseController
5
2
  include PropelAuthenticationConcern
6
3
 
7
4
  before_action :authenticate_user, only: [:show, :refresh]
@@ -42,7 +39,7 @@ class <%= auth_controller_class_name('tokens') %> < ApplicationController
42
39
  render json: { error: 'Invalid credentials' }, status: :unauthorized
43
40
  end
44
41
  rescue ActionController::ParameterMissing
45
- render json: { error: 'Missing required parameters' }, status: :unprocessable_content
42
+ render json: { error: 'Missing required parameters' }, status: :bad_request
46
43
  end
47
44
 
48
45
  # DELETE <%= auth_route_prefix %>/logout
@@ -50,11 +50,14 @@ module PropelAuthentication
50
50
 
51
51
 
52
52
  # Single method to determine all authentication configuration
53
- # Handles namespace, version, and auth_scope with consistent priority logic
53
+ # Handles namespace, version, auth_scope, and tenancy options with consistent priority logic
54
54
  def determine_configuration
55
55
  @auth_namespace = determine_config_value(:namespace, nil)
56
56
  @auth_version = determine_config_value(:version, nil)
57
57
  @auth_scope = determine_config_value(:auth_scope, nil)
58
+ @tenancy_enabled = determine_tenancy_enabled
59
+ @organization_required = determine_organization_required
60
+ @agency_required = determine_agency_required
58
61
  end
59
62
 
60
63
  # Generic configuration value determination with consistent priority
@@ -187,5 +190,39 @@ module PropelAuthentication
187
190
 
188
191
  path_parts.join('/')
189
192
  end
193
+
194
+ # Determine tenancy_enabled configuration
195
+ # Priority: 1) Command line option, 2) Default (true)
196
+ def determine_tenancy_enabled
197
+ return options[:tenancy_enabled] unless options[:tenancy_enabled].nil?
198
+ true # Default to enabled
199
+ end
200
+
201
+ # Determine organization_required configuration
202
+ # Priority: 1) Command line option, 2) Default (true)
203
+ def determine_organization_required
204
+ return options[:organization_required] unless options[:organization_required].nil?
205
+ true # Default to required
206
+ end
207
+
208
+ # Determine agency_required configuration
209
+ # Priority: 1) Command line option, 2) Default (true)
210
+ def determine_agency_required
211
+ return options[:agency_required] unless options[:agency_required].nil?
212
+ true # Default to required
213
+ end
214
+
215
+ # Accessor methods for templates
216
+ def tenancy_enabled?
217
+ @tenancy_enabled
218
+ end
219
+
220
+ def organization_required?
221
+ @organization_required
222
+ end
223
+
224
+ def agency_required?
225
+ @agency_required
226
+ end
190
227
  end
191
228
  end
@@ -2,7 +2,9 @@ class CreateAgencies < ActiveRecord::Migration[8.0]
2
2
  def change
3
3
  create_table :agencies do |t|
4
4
  t.string :name, null: false
5
+ <% if PropelAuthentication.configuration.organization_required? %>
5
6
  t.references :organization, null: false, foreign_key: true
7
+ <% end %>
6
8
  t.string :phone_number
7
9
  t.string :address
8
10
  t.string :time_zone