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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +60 -0
- data/lib/generators/propel_authentication/install_generator.rb +190 -228
- data/lib/generators/propel_authentication/templates/auth/passwords_controller.rb.tt +10 -13
- data/lib/generators/propel_authentication/templates/auth/signup_controller.rb.tt +6 -9
- data/lib/generators/propel_authentication/templates/auth/tokens_controller.rb.tt +4 -7
- data/lib/generators/propel_authentication/templates/core/configuration_methods.rb +38 -1
- data/lib/generators/propel_authentication/templates/db/migrate/create_agencies.rb +4 -2
- data/lib/generators/propel_authentication/templates/db/migrate/create_agents.rb +6 -1
- data/lib/generators/propel_authentication/templates/db/migrate/create_organizations.rb +4 -2
- data/lib/generators/propel_authentication/templates/db/migrate/create_users.rb +4 -2
- 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 +8 -2
- data/lib/generators/propel_authentication/templates/models/agent.rb.tt +13 -2
- data/lib/generators/propel_authentication/templates/models/invitation.rb.tt +3 -1
- data/lib/generators/propel_authentication/templates/models/organization.rb.tt +15 -2
- data/lib/generators/propel_authentication/templates/models/user.rb.tt +18 -2
- 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 +2 -2
- data/lib/generators/propel_authentication/templates/test/controllers/auth/password_reset_integration_test.rb.tt +9 -9
- data/lib/generators/propel_authentication/templates/test/controllers/auth/signup_controller_test.rb.tt +6 -6
- data/lib/generators/propel_authentication/templates/test/controllers/auth/tokens_controller_test.rb.tt +4 -4
- data/lib/generators/propel_authentication/test/generators/authentication/controllers/tokens_controller_test.rb +1 -1
- data/lib/generators/propel_authentication/test/generators/authentication/install_generator_test.rb +1 -1
- data/lib/generators/propel_authentication/test/integration/multi_version_generator_test.rb +12 -13
- data/lib/propel_authentication.rb +1 -1
- metadata +30 -5
- 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,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
|
-
|
|
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
|
-
add_gem_if_missing('jwt', '~> 2
|
|
120
|
-
add_gem_if_missing('
|
|
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
|
|
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,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') %> <
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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: :
|
|
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') %> <
|
|
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: :
|
|
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.
|
|
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: :
|
|
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: :
|
|
233
|
+
}, status: :unprocessable_content
|
|
237
234
|
return false
|
|
238
235
|
end
|
|
239
236
|
|