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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -0
- data/lib/generators/propel_authentication/install_generator.rb +188 -240
- data/lib/generators/propel_authentication/templates/auth/passwords_controller.rb.tt +1 -4
- data/lib/generators/propel_authentication/templates/auth/signup_controller.rb.tt +3 -6
- data/lib/generators/propel_authentication/templates/auth/tokens_controller.rb.tt +2 -5
- data/lib/generators/propel_authentication/templates/core/configuration_methods.rb +38 -1
- data/lib/generators/propel_authentication/templates/db/migrate/create_agencies.rb +2 -0
- data/lib/generators/propel_authentication/templates/db/migrate/create_agents.rb +6 -1
- data/lib/generators/propel_authentication/templates/db/migrate/create_users.rb +2 -0
- data/lib/generators/propel_authentication/templates/db/propel_seeds.rb.tt +145 -0
- data/lib/generators/propel_authentication/templates/doc/signup_flow.md +9 -4
- data/lib/generators/propel_authentication/templates/fixtures/agencies.yml.erb +23 -0
- data/lib/generators/propel_authentication/templates/fixtures/agents.yml.erb +71 -0
- data/lib/generators/propel_authentication/templates/fixtures/invitations.yml.erb +9 -0
- data/lib/generators/propel_authentication/templates/fixtures/organizations.yml.erb +21 -0
- data/lib/generators/propel_authentication/templates/fixtures/users.yml.erb +77 -0
- data/lib/generators/propel_authentication/templates/models/agency.rb.tt +4 -0
- data/lib/generators/propel_authentication/templates/models/agent.rb.tt +9 -0
- data/lib/generators/propel_authentication/templates/models/invitation.rb.tt +3 -1
- data/lib/generators/propel_authentication/templates/models/organization.rb.tt +3 -0
- data/lib/generators/propel_authentication/templates/propel_authentication.rb.tt +33 -6
- 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 +1 -1
- data/lib/generators/propel_authentication/templates/test/controllers/auth/tokens_controller_test.rb.tt +4 -4
- data/lib/propel_authentication.rb +1 -1
- metadata +8 -3
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b951cffb4dd4a53fd4f5b16e3f30f97a4fb4e4dae4999f30aeb6ea3ca44bd1f
|
4
|
+
data.tar.gz: c8077baca253a2a5ab7770f75043a948adb7fa7e922572c4bd898c0c7fcb979a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
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') %> <
|
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') %> <
|
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.
|
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') %> <
|
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: :
|
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
|
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
|