propel_authentication 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +290 -0
- data/Rakefile +12 -0
- data/lib/generators/propel_auth/install_generator.rb +486 -0
- data/lib/generators/propel_auth/pack_generator.rb +277 -0
- data/lib/generators/propel_auth/templates/agency.rb +7 -0
- data/lib/generators/propel_auth/templates/agent.rb +7 -0
- data/lib/generators/propel_auth/templates/auth/base_passwords_controller.rb.tt +99 -0
- data/lib/generators/propel_auth/templates/auth/base_tokens_controller.rb.tt +90 -0
- data/lib/generators/propel_auth/templates/auth/passwords_controller.rb.tt +126 -0
- data/lib/generators/propel_auth/templates/auth_mailer.rb +180 -0
- data/lib/generators/propel_auth/templates/authenticatable.rb +38 -0
- data/lib/generators/propel_auth/templates/concerns/confirmable.rb +145 -0
- data/lib/generators/propel_auth/templates/concerns/lockable.rb +123 -0
- data/lib/generators/propel_auth/templates/concerns/propel_authentication.rb +44 -0
- data/lib/generators/propel_auth/templates/concerns/rack_session_disable.rb +19 -0
- data/lib/generators/propel_auth/templates/concerns/recoverable.rb +124 -0
- data/lib/generators/propel_auth/templates/config/environments/development_email.rb +43 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_agencies.rb +20 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_agents.rb +11 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_invitations.rb +28 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_organizations.rb +18 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_users.rb +43 -0
- data/lib/generators/propel_auth/templates/db/seeds.rb +29 -0
- data/lib/generators/propel_auth/templates/invitation.rb +133 -0
- data/lib/generators/propel_auth/templates/lib/propel_auth.rb +84 -0
- data/lib/generators/propel_auth/templates/organization.rb +7 -0
- data/lib/generators/propel_auth/templates/propel_auth.rb +132 -0
- data/lib/generators/propel_auth/templates/services/auth_notification_service.rb +89 -0
- data/lib/generators/propel_auth/templates/test/concerns/confirmable_test.rb.tt +247 -0
- data/lib/generators/propel_auth/templates/test/concerns/lockable_test.rb.tt +282 -0
- data/lib/generators/propel_auth/templates/test/concerns/propel_authentication_test.rb.tt +75 -0
- data/lib/generators/propel_auth/templates/test/concerns/recoverable_test.rb.tt +327 -0
- data/lib/generators/propel_auth/templates/test/controllers/auth/lockable_integration_test.rb.tt +196 -0
- data/lib/generators/propel_auth/templates/test/controllers/auth/password_reset_integration_test.rb.tt +471 -0
- data/lib/generators/propel_auth/templates/test/controllers/auth/tokens_controller_test.rb.tt +265 -0
- data/lib/generators/propel_auth/templates/test/mailers/auth_mailer_test.rb.tt +216 -0
- data/lib/generators/propel_auth/templates/test/mailers/previews/auth_mailer_preview.rb +161 -0
- data/lib/generators/propel_auth/templates/tokens_controller.rb.tt +96 -0
- data/lib/generators/propel_auth/templates/user.rb +21 -0
- data/lib/generators/propel_auth/templates/user_test.rb.tt +81 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/account_unlock.html.erb +213 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/account_unlock.text.erb +56 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/email_confirmation.html.erb +213 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/email_confirmation.text.erb +32 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/password_reset.html.erb +166 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/password_reset.text.erb +32 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/user_invitation.html.erb +194 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/user_invitation.text.erb +51 -0
- data/lib/generators/propel_auth/test/dummy/Dockerfile +72 -0
- data/lib/generators/propel_auth/test/dummy/Gemfile +63 -0
- data/lib/generators/propel_auth/test/dummy/Gemfile.lock +394 -0
- data/lib/generators/propel_auth/test/dummy/README.md +24 -0
- data/lib/generators/propel_auth/test/dummy/Rakefile +6 -0
- data/lib/generators/propel_auth/test/dummy/app/assets/stylesheets/application.css +10 -0
- data/lib/generators/propel_auth/test/dummy/app/controllers/application_controller.rb +4 -0
- data/lib/generators/propel_auth/test/dummy/app/helpers/application_helper.rb +2 -0
- data/lib/generators/propel_auth/test/dummy/app/jobs/application_job.rb +7 -0
- data/lib/generators/propel_auth/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/lib/generators/propel_auth/test/dummy/app/models/application_record.rb +3 -0
- data/lib/generators/propel_auth/test/dummy/app/views/layouts/application.html.erb +27 -0
- data/lib/generators/propel_auth/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/lib/generators/propel_auth/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/lib/generators/propel_auth/test/dummy/app/views/pwa/manifest.json.erb +22 -0
- data/lib/generators/propel_auth/test/dummy/app/views/pwa/service-worker.js +26 -0
- data/lib/generators/propel_auth/test/dummy/bin/brakeman +7 -0
- data/lib/generators/propel_auth/test/dummy/bin/dev +2 -0
- data/lib/generators/propel_auth/test/dummy/bin/docker-entrypoint +14 -0
- data/lib/generators/propel_auth/test/dummy/bin/rails +4 -0
- data/lib/generators/propel_auth/test/dummy/bin/rake +4 -0
- data/lib/generators/propel_auth/test/dummy/bin/rubocop +8 -0
- data/lib/generators/propel_auth/test/dummy/bin/setup +34 -0
- data/lib/generators/propel_auth/test/dummy/bin/thrust +5 -0
- data/lib/generators/propel_auth/test/dummy/config/application.rb +42 -0
- data/lib/generators/propel_auth/test/dummy/config/boot.rb +4 -0
- data/lib/generators/propel_auth/test/dummy/config/cable.yml +10 -0
- data/lib/generators/propel_auth/test/dummy/config/credentials.yml.enc +1 -0
- data/lib/generators/propel_auth/test/dummy/config/database.yml +41 -0
- data/lib/generators/propel_auth/test/dummy/config/environment.rb +5 -0
- data/lib/generators/propel_auth/test/dummy/config/environments/development.rb +72 -0
- data/lib/generators/propel_auth/test/dummy/config/environments/production.rb +89 -0
- data/lib/generators/propel_auth/test/dummy/config/environments/test.rb +53 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/assets.rb +10 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/content_security_policy.rb +25 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/inflections.rb +16 -0
- data/lib/generators/propel_auth/test/dummy/config/locales/en.yml +31 -0
- data/lib/generators/propel_auth/test/dummy/config/master.key +1 -0
- data/lib/generators/propel_auth/test/dummy/config/puma.rb +41 -0
- data/lib/generators/propel_auth/test/dummy/config/routes.rb +2 -0
- data/lib/generators/propel_auth/test/dummy/config/storage.yml +34 -0
- data/lib/generators/propel_auth/test/dummy/config.ru +6 -0
- data/lib/generators/propel_auth/test/dummy/db/schema.rb +14 -0
- data/lib/generators/propel_auth/test/generators/authentication/controllers/tokens_controller_test.rb +230 -0
- data/lib/generators/propel_auth/test/generators/authentication/install_generator_test.rb +490 -0
- data/lib/generators/propel_auth/test/generators/authentication/uninstall_generator_test.rb +408 -0
- data/lib/generators/propel_auth/test/integration/generator_integration_test.rb +158 -0
- data/lib/generators/propel_auth/test/integration/multi_version_generator_test.rb +125 -0
- data/lib/generators/propel_auth/unpack_generator.rb +345 -0
- data/lib/propel_auth.rb +3 -0
- metadata +195 -0
@@ -0,0 +1,486 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
require_relative 'unpack_generator'
|
4
|
+
##
|
5
|
+
# PropelAuth installer that provides JWT-based authentication for Rails applications
|
6
|
+
#
|
7
|
+
# This creates a COMPLETELY STANDALONE authentication system with no gem dependencies.
|
8
|
+
# Usage:
|
9
|
+
# rails generate propel_auth:install # Full standalone system (runtime + generators)
|
10
|
+
#
|
11
|
+
# This generator:
|
12
|
+
# 1. Installs all runtime code (models, controllers, views, tests, etc.)
|
13
|
+
# 2. Automatically extracts generator logic to lib/generators/propel_auth/
|
14
|
+
# 3. Creates a system that requires NO gem dependencies
|
15
|
+
#
|
16
|
+
# After installation, you can remove 'propel_auth' from your Gemfile completely.
|
17
|
+
# All code is in your application and fully customizable.
|
18
|
+
#
|
19
|
+
# Like Rails' built-in generators (action_text:install, devise:install),
|
20
|
+
# this generator is designed to be run once per application.
|
21
|
+
#
|
22
|
+
module PropelAuth
|
23
|
+
class InstallGenerator < Rails::Generators::Base
|
24
|
+
source_root File.expand_path("templates", __dir__)
|
25
|
+
include Rails::Generators::Migration
|
26
|
+
|
27
|
+
def self.next_migration_number(dir)
|
28
|
+
ActiveRecord::Generators::Base.next_migration_number(dir)
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Generate JWT-based authentication system with complete test coverage"
|
32
|
+
|
33
|
+
class_option :api_version, type: :string, default: nil,
|
34
|
+
desc: "Generate API versioned routes with specified version (e.g., --api-version=v2 creates /api/v2/auth/*)"
|
35
|
+
|
36
|
+
def copy_jwt_initializer
|
37
|
+
copy_file "propel_auth.rb", "config/initializers/propel_auth.rb"
|
38
|
+
end
|
39
|
+
|
40
|
+
def copy_propel_auth_runtime
|
41
|
+
copy_file "lib/propel_auth.rb", "lib/propel_auth.rb"
|
42
|
+
end
|
43
|
+
|
44
|
+
def copy_authentication_models
|
45
|
+
copy_file "user.rb", "app/models/user.rb"
|
46
|
+
copy_file "organization.rb", "app/models/organization.rb"
|
47
|
+
copy_file "agency.rb", "app/models/agency.rb"
|
48
|
+
copy_file "agent.rb", "app/models/agent.rb"
|
49
|
+
copy_file "invitation.rb", "app/models/invitation.rb"
|
50
|
+
end
|
51
|
+
|
52
|
+
def copy_authentication_concerns
|
53
|
+
copy_file "authenticatable.rb", "app/models/concerns/authenticatable.rb"
|
54
|
+
copy_file "concerns/lockable.rb", "app/models/concerns/lockable.rb"
|
55
|
+
copy_file "concerns/recoverable.rb", "app/models/concerns/recoverable.rb"
|
56
|
+
copy_file "concerns/confirmable.rb", "app/models/concerns/confirmable.rb"
|
57
|
+
copy_file "concerns/propel_authentication.rb", "app/controllers/concerns/propel_authentication.rb"
|
58
|
+
copy_file "concerns/rack_session_disable.rb", "app/controllers/concerns/rack_session_disable.rb"
|
59
|
+
end
|
60
|
+
|
61
|
+
def copy_jwt_controllers
|
62
|
+
if api_versioned?
|
63
|
+
template "auth/base_tokens_controller.rb.tt", "app/controllers/api/auth/base_tokens_controller.rb"
|
64
|
+
template "auth/base_passwords_controller.rb.tt", "app/controllers/api/auth/base_passwords_controller.rb"
|
65
|
+
create_versioned_controller(api_version, 'tokens', controller_directory)
|
66
|
+
create_versioned_controller(api_version, 'passwords', controller_directory)
|
67
|
+
else
|
68
|
+
template "tokens_controller.rb.tt", "#{controller_directory}/tokens_controller.rb"
|
69
|
+
template "auth/passwords_controller.rb.tt", "#{controller_directory}/passwords_controller.rb"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def copy_email_infrastructure
|
74
|
+
copy_file "auth_mailer.rb", "app/mailers/auth_mailer.rb"
|
75
|
+
copy_file "services/auth_notification_service.rb", "app/services/auth_notification_service.rb"
|
76
|
+
copy_file "config/environments/development_email.rb", "config/environments/development_email.rb"
|
77
|
+
|
78
|
+
# Email view templates
|
79
|
+
%w[password_reset account_unlock user_invitation email_confirmation].each do |template|
|
80
|
+
copy_file "views/auth_mailer/#{template}.html.erb", "app/views/auth_mailer/#{template}.html.erb"
|
81
|
+
copy_file "views/auth_mailer/#{template}.text.erb", "app/views/auth_mailer/#{template}.text.erb"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def copy_authentication_tests
|
86
|
+
template "user_test.rb.tt", "test/models/user_test.rb"
|
87
|
+
template "test/controllers/auth/tokens_controller_test.rb.tt", "test/controllers/auth/tokens_controller_test.rb"
|
88
|
+
template "test/mailers/auth_mailer_test.rb.tt", "test/mailers/auth_mailer_test.rb"
|
89
|
+
copy_file "test/mailers/previews/auth_mailer_preview.rb", "test/mailers/previews/auth_mailer_preview.rb"
|
90
|
+
end
|
91
|
+
|
92
|
+
def copy_concern_tests
|
93
|
+
template "test/concerns/propel_authentication_test.rb.tt", "test/concerns/propel_authentication_test.rb"
|
94
|
+
template "test/concerns/lockable_test.rb.tt", "test/concerns/lockable_test.rb"
|
95
|
+
template "test/concerns/recoverable_test.rb.tt", "test/concerns/recoverable_test.rb"
|
96
|
+
template "test/concerns/confirmable_test.rb.tt", "test/concerns/confirmable_test.rb"
|
97
|
+
template "test/controllers/auth/lockable_integration_test.rb.tt", "test/controllers/auth/lockable_integration_test.rb"
|
98
|
+
template "test/controllers/auth/password_reset_integration_test.rb.tt", "test/controllers/auth/password_reset_integration_test.rb"
|
99
|
+
end
|
100
|
+
|
101
|
+
def copy_test_fixtures
|
102
|
+
create_file "test/fixtures/organizations.yml", organizations_fixture
|
103
|
+
create_file "test/fixtures/users.yml", users_fixture
|
104
|
+
create_file "test/fixtures/agencies.yml", agencies_fixture
|
105
|
+
create_file "test/fixtures/agents.yml", agents_fixture
|
106
|
+
create_file "test/fixtures/invitations.yml", invitations_fixture
|
107
|
+
end
|
108
|
+
|
109
|
+
def add_authentication_gems
|
110
|
+
add_gem_if_missing('bcrypt', '~> 3.1.20')
|
111
|
+
add_gem_if_missing('jwt', '~> 2.7')
|
112
|
+
add_gem_if_missing('letter_opener', '~> 1.8', group: :development)
|
113
|
+
end
|
114
|
+
|
115
|
+
def add_authentication_routes
|
116
|
+
route generate_routes_content
|
117
|
+
end
|
118
|
+
|
119
|
+
def copy_authentication_migrations
|
120
|
+
%w[organizations users agencies agents invitations].each do |table|
|
121
|
+
unless migration_exists?("create_#{table}")
|
122
|
+
migration_template "db/migrate/create_#{table}.rb", "db/migrate/create_#{table}.rb"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def copy_database_seeds
|
128
|
+
copy_file "db/seeds.rb", "db/seeds.rb"
|
129
|
+
end
|
130
|
+
|
131
|
+
def extract_generator_for_customization
|
132
|
+
generator_path = "lib/generators/propel_auth"
|
133
|
+
|
134
|
+
if File.exist?(generator_path)
|
135
|
+
say ""
|
136
|
+
say "📦 Generator logic already extracted at #{generator_path}/", :blue
|
137
|
+
say "💡 Skipping extraction to preserve your customizations", :cyan
|
138
|
+
else
|
139
|
+
say ""
|
140
|
+
say "📦 Extracting generator logic for full customization...", :blue
|
141
|
+
|
142
|
+
# Automatically run the unpack generator to extract generator logic
|
143
|
+
invoke PropelAuth::UnpackGenerator, [], { force: false }
|
144
|
+
|
145
|
+
say ""
|
146
|
+
say "✅ Generator logic extracted to lib/generators/propel_auth/", :green
|
147
|
+
say "💡 Your application is now completely standalone - no gem dependency needed for generators!", :cyan
|
148
|
+
say "🗑️ You can now remove 'propel_auth' from your Gemfile", :yellow
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def show_setup_complete_message
|
153
|
+
say "\n🚀 JWT Authentication System Generated Successfully!", :green
|
154
|
+
|
155
|
+
say "\n📦 System Status: Completely standalone - no gem dependency!", :green
|
156
|
+
say "\nNext steps:", :yellow
|
157
|
+
say "• Run: rails db:migrate", :blue
|
158
|
+
say "• Run: rails test", :blue
|
159
|
+
say "• Optional: Remove 'propel_auth' from Gemfile (system is fully extracted)", :cyan
|
160
|
+
|
161
|
+
if api_versioned?
|
162
|
+
say "• Routes: /#{api_namespace}/auth/*", :blue
|
163
|
+
say "• Controllers: #{controller_namespace}::*", :blue
|
164
|
+
else
|
165
|
+
say "• Routes: /auth/*", :blue
|
166
|
+
say "• Controllers: Auth::*", :blue
|
167
|
+
end
|
168
|
+
|
169
|
+
say "\n🎨 Customization:", :bold
|
170
|
+
say "• Generator logic: lib/generators/propel_auth/install_generator.rb", :blue
|
171
|
+
say "• Templates: lib/generators/propel_auth/templates/", :blue
|
172
|
+
say "• Modify any part of the system - it's all yours now!", :cyan
|
173
|
+
|
174
|
+
say "\n🗑️ To uninstall: rails destroy propel_auth:install", :yellow
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
# Helper methods for API versioning
|
180
|
+
def api_versioned?
|
181
|
+
options[:api_version].present?
|
182
|
+
end
|
183
|
+
|
184
|
+
def api_version
|
185
|
+
options[:api_version] || 'v1'
|
186
|
+
end
|
187
|
+
|
188
|
+
def api_namespace
|
189
|
+
"api/#{api_version}"
|
190
|
+
end
|
191
|
+
|
192
|
+
def api_namespace_parts
|
193
|
+
api_namespace.split('/')
|
194
|
+
end
|
195
|
+
|
196
|
+
def controller_namespace
|
197
|
+
if api_versioned?
|
198
|
+
api_namespace_parts.map(&:camelize).join('::') + '::Auth'
|
199
|
+
else
|
200
|
+
'Auth'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def controller_directory
|
205
|
+
if api_versioned?
|
206
|
+
"app/controllers/#{api_namespace}/auth"
|
207
|
+
else
|
208
|
+
"app/controllers/auth"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def api_only_app?
|
213
|
+
# Check if this is a Rails API-only application
|
214
|
+
Rails.application.config.respond_to?(:api_only) && Rails.application.config.api_only
|
215
|
+
end
|
216
|
+
|
217
|
+
# Path helper methods for tests
|
218
|
+
def login_path_helper
|
219
|
+
if api_versioned?
|
220
|
+
"'/#{api_namespace}/auth/login'"
|
221
|
+
else
|
222
|
+
"'/auth/login'"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def me_path_helper
|
227
|
+
if api_versioned?
|
228
|
+
"'/#{api_namespace}/auth/me'"
|
229
|
+
else
|
230
|
+
"'/auth/me'"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def logout_path_helper
|
235
|
+
if api_versioned?
|
236
|
+
"'/#{api_namespace}/auth/logout'"
|
237
|
+
else
|
238
|
+
"'/auth/logout'"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def unlock_path_helper
|
243
|
+
if api_versioned?
|
244
|
+
"'/#{api_namespace}/auth/unlock'"
|
245
|
+
else
|
246
|
+
"'/auth/unlock'"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def password_reset_path_helper
|
251
|
+
if api_versioned?
|
252
|
+
"'/#{api_namespace}/auth/reset'"
|
253
|
+
else
|
254
|
+
"'/auth/reset'"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def reset_path_helper
|
259
|
+
password_reset_path_helper
|
260
|
+
end
|
261
|
+
|
262
|
+
def add_gem_if_missing(gem_name, version_requirement = nil, options = {})
|
263
|
+
gemfile_path = File.join(destination_root, 'Gemfile')
|
264
|
+
return unless File.exist?(gemfile_path)
|
265
|
+
|
266
|
+
gemfile_content = File.read(gemfile_path)
|
267
|
+
|
268
|
+
# Check if gem is already present (handles various quote styles and spacing)
|
269
|
+
gem_pattern = /gem\s+['"]#{Regexp.escape(gem_name)}['"](?:\s*,\s*['"][^'"]*['"])?/
|
270
|
+
|
271
|
+
if gemfile_content.match?(gem_pattern)
|
272
|
+
say_status :exists, "gem '#{gem_name}' already in Gemfile", :blue
|
273
|
+
return
|
274
|
+
end
|
275
|
+
|
276
|
+
# Add the gem using Rails' built-in method
|
277
|
+
if version_requirement && options.any?
|
278
|
+
gem gem_name, version_requirement, options
|
279
|
+
elsif version_requirement
|
280
|
+
gem gem_name, version_requirement
|
281
|
+
else
|
282
|
+
gem gem_name
|
283
|
+
end
|
284
|
+
|
285
|
+
say_status :gemfile, "gem '#{gem_name}' #{version_requirement}", :green
|
286
|
+
end
|
287
|
+
|
288
|
+
def migration_exists?(migration_name)
|
289
|
+
Dir.glob("#{destination_root}/db/migrate/*_#{migration_name}.rb").any?
|
290
|
+
end
|
291
|
+
|
292
|
+
def generate_routes_content
|
293
|
+
if api_versioned?
|
294
|
+
route_lines = ["# JWT Authentication routes for #{api_namespace}"]
|
295
|
+
|
296
|
+
# Build nested namespace opening
|
297
|
+
api_namespace_parts.each_with_index do |part, index|
|
298
|
+
indent = " " * index
|
299
|
+
route_lines << "#{indent}namespace :#{part} do"
|
300
|
+
end
|
301
|
+
|
302
|
+
# Add auth namespace and routes
|
303
|
+
auth_indent = " " * api_namespace_parts.length
|
304
|
+
route_lines << "#{auth_indent}namespace :auth do"
|
305
|
+
route_lines << "#{auth_indent} post 'login', to: 'tokens#create'"
|
306
|
+
route_lines << "#{auth_indent} get 'me', to: 'tokens#me'"
|
307
|
+
route_lines << "#{auth_indent} delete 'logout', to: 'tokens#destroy'"
|
308
|
+
route_lines << "#{auth_indent} post 'unlock', to: 'tokens#unlock'"
|
309
|
+
route_lines << "#{auth_indent} post 'reset', to: 'passwords#create'"
|
310
|
+
route_lines << "#{auth_indent} get 'reset', to: 'passwords#show'"
|
311
|
+
route_lines << "#{auth_indent} patch 'reset', to: 'passwords#update'"
|
312
|
+
route_lines << "#{auth_indent}end"
|
313
|
+
|
314
|
+
# Build nested namespace closing
|
315
|
+
api_namespace_parts.length.times do |index|
|
316
|
+
indent = " " * (api_namespace_parts.length - 1 - index)
|
317
|
+
route_lines << "#{indent}end"
|
318
|
+
end
|
319
|
+
|
320
|
+
route_lines.join("\n")
|
321
|
+
else
|
322
|
+
<<~ROUTES
|
323
|
+
# JWT Authentication routes
|
324
|
+
namespace :auth do
|
325
|
+
post 'login', to: 'tokens#create'
|
326
|
+
get 'me', to: 'tokens#me'
|
327
|
+
delete 'logout', to: 'tokens#destroy'
|
328
|
+
post 'unlock', to: 'tokens#unlock'
|
329
|
+
post 'reset', to: 'passwords#create'
|
330
|
+
get 'reset', to: 'passwords#show'
|
331
|
+
patch 'reset', to: 'passwords#update'
|
332
|
+
end
|
333
|
+
ROUTES
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def create_versioned_controller(version, controller_type, directory)
|
338
|
+
case controller_type
|
339
|
+
when 'tokens'
|
340
|
+
controller_content = <<~RUBY
|
341
|
+
# Generated versioned controller for API #{version}
|
342
|
+
class Api::#{version.camelize}::Auth::TokensController < Api::Auth::BaseTokensController
|
343
|
+
end
|
344
|
+
RUBY
|
345
|
+
when 'passwords'
|
346
|
+
controller_content = <<~RUBY
|
347
|
+
# Generated versioned controller for API #{version}
|
348
|
+
class Api::#{version.camelize}::Auth::PasswordsController < Api::Auth::BasePasswordsController
|
349
|
+
end
|
350
|
+
RUBY
|
351
|
+
end
|
352
|
+
|
353
|
+
create_file "#{directory}/#{controller_type}_controller.rb", controller_content
|
354
|
+
end
|
355
|
+
|
356
|
+
# Fixture content methods
|
357
|
+
def organizations_fixture
|
358
|
+
<<~FIXTURE
|
359
|
+
acme_org:
|
360
|
+
name: "Acme Corporation"
|
361
|
+
website: "https://acme-corp.com"
|
362
|
+
time_zone: "UTC"
|
363
|
+
meta: {}
|
364
|
+
settings: {}
|
365
|
+
created_at: <%= 30.days.ago %>
|
366
|
+
updated_at: <%= 1.day.ago %>
|
367
|
+
|
368
|
+
tech_startup:
|
369
|
+
name: "Tech Startup Inc"
|
370
|
+
website: "https://techstartup.io"
|
371
|
+
time_zone: "America/New_York"
|
372
|
+
meta: {}
|
373
|
+
settings: {}
|
374
|
+
created_at: <%= 15.days.ago %>
|
375
|
+
updated_at: <%= 2.days.ago %>
|
376
|
+
FIXTURE
|
377
|
+
end
|
378
|
+
|
379
|
+
def users_fixture
|
380
|
+
<<~FIXTURE
|
381
|
+
john_user:
|
382
|
+
email_address: "john@example.com"
|
383
|
+
username: "john_doe"
|
384
|
+
first_name: "John"
|
385
|
+
last_name: "Doe"
|
386
|
+
password_digest: "<%= BCrypt::Password.create('password123') %>"
|
387
|
+
organization: acme_org
|
388
|
+
status: "active"
|
389
|
+
confirmed_at: null
|
390
|
+
confirmation_token: "<%= SecureRandom.hex(32) %>"
|
391
|
+
confirmation_sent_at: <%= 1.hour.ago %>
|
392
|
+
created_at: <%= 7.days.ago %>
|
393
|
+
updated_at: <%= 1.day.ago %>
|
394
|
+
|
395
|
+
jane_user:
|
396
|
+
email_address: "jane@example.com"
|
397
|
+
username: "jane_smith"
|
398
|
+
first_name: "Jane"
|
399
|
+
last_name: "Smith"
|
400
|
+
password_digest: "<%= BCrypt::Password.create('password123') %>"
|
401
|
+
organization: tech_startup
|
402
|
+
status: "active"
|
403
|
+
confirmed_at: null
|
404
|
+
failed_login_attempts: 0
|
405
|
+
locked_at: null
|
406
|
+
created_at: <%= 5.days.ago %>
|
407
|
+
updated_at: <%= 1.day.ago %>
|
408
|
+
|
409
|
+
confirmed_user:
|
410
|
+
email_address: "confirmed@example.com"
|
411
|
+
username: "confirmed_user"
|
412
|
+
first_name: "Confirmed"
|
413
|
+
last_name: "User"
|
414
|
+
password_digest: "<%= BCrypt::Password.create('password123') %>"
|
415
|
+
organization: acme_org
|
416
|
+
status: "active"
|
417
|
+
confirmed_at: <%= 7.days.ago %>
|
418
|
+
created_at: <%= 14.days.ago %>
|
419
|
+
updated_at: <%= 1.day.ago %>
|
420
|
+
|
421
|
+
locked_user:
|
422
|
+
email_address: "locked@example.com"
|
423
|
+
username: "locked_user"
|
424
|
+
first_name: "Locked"
|
425
|
+
last_name: "User"
|
426
|
+
password_digest: "<%= BCrypt::Password.create('password123') %>"
|
427
|
+
organization: acme_org
|
428
|
+
status: "active"
|
429
|
+
confirmed_at: <%= 10.days.ago %>
|
430
|
+
failed_login_attempts: 5
|
431
|
+
locked_at: <%= 1.hour.ago %>
|
432
|
+
created_at: <%= 20.days.ago %>
|
433
|
+
updated_at: <%= 1.hour.ago %>
|
434
|
+
|
435
|
+
expired_confirmation_user:
|
436
|
+
email_address: "expired@example.com"
|
437
|
+
username: "expired_user"
|
438
|
+
first_name: "Expired"
|
439
|
+
last_name: "User"
|
440
|
+
password_digest: "<%= BCrypt::Password.create('password123') %>"
|
441
|
+
organization: tech_startup
|
442
|
+
status: "active"
|
443
|
+
confirmed_at: null
|
444
|
+
confirmation_token: "<%= SecureRandom.hex(32) %>"
|
445
|
+
confirmation_sent_at: <%= 25.hours.ago %>
|
446
|
+
created_at: <%= 30.days.ago %>
|
447
|
+
updated_at: <%= 25.hours.ago %>
|
448
|
+
FIXTURE
|
449
|
+
end
|
450
|
+
|
451
|
+
def agencies_fixture
|
452
|
+
<<~FIXTURE
|
453
|
+
marketing_agency:
|
454
|
+
name: "Marketing Solutions"
|
455
|
+
organization: acme_org
|
456
|
+
created_at: <%= 10.days.ago %>
|
457
|
+
updated_at: <%= 2.days.ago %>
|
458
|
+
FIXTURE
|
459
|
+
end
|
460
|
+
|
461
|
+
def agents_fixture
|
462
|
+
<<~FIXTURE
|
463
|
+
marketing_agent:
|
464
|
+
user: john_user
|
465
|
+
agency: marketing_agency
|
466
|
+
role: "manager"
|
467
|
+
created_at: <%= 8.days.ago %>
|
468
|
+
updated_at: <%= 1.day.ago %>
|
469
|
+
FIXTURE
|
470
|
+
end
|
471
|
+
|
472
|
+
def invitations_fixture
|
473
|
+
<<~FIXTURE
|
474
|
+
pending_invitation:
|
475
|
+
email_address: "newuser@example.com"
|
476
|
+
first_name: "New"
|
477
|
+
last_name: "User"
|
478
|
+
organization: acme_org
|
479
|
+
inviter: john_user
|
480
|
+
status: "pending"
|
481
|
+
created_at: <%= 3.days.ago %>
|
482
|
+
updated_at: <%= 3.days.ago %>
|
483
|
+
FIXTURE
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|