b4um_generators 0.2.17 → 0.4.0
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 +30 -0
- data/README.de.md +418 -4
- data/README.md +405 -5
- data/lib/b4um_generators/version.rb +1 -1
- data/lib/generators/b4um/admin/admin_generator.rb +614 -0
- data/lib/generators/b4um/admin/templates/add_admin_fields_migration.rb.tt +10 -0
- data/lib/generators/b4um/admin/templates/admin_base_controller.rb.tt +5 -0
- data/lib/generators/b4um/admin/templates/admin_dashboard.html.erb.tt +19 -0
- data/lib/generators/b4um/admin/templates/admin_dashboard_controller.rb.tt +6 -0
- data/lib/generators/b4um/admin/templates/admin_users_controller.rb.tt +70 -0
- data/lib/generators/b4um/admin/templates/admin_users_index.html.erb.tt +110 -0
- data/lib/generators/b4um/admin/templates/b4um_admin.rake.tt +106 -0
- data/lib/generators/b4um/authentication/authentication_generator.rb +90 -1
- data/lib/generators/b4um/guest/guest_generator.rb +673 -0
- data/lib/generators/b4um/guest/templates/add_guest_fields_migration.rb.tt +12 -0
- data/lib/generators/b4um/guest/templates/b4um_guests.rake.tt +12 -0
- data/lib/generators/b4um/guest/templates/edit.html.erb.tt +156 -0
- data/lib/generators/b4um/guest/templates/guest_expiration_warning.html.erb.tt +12 -0
- data/lib/generators/b4um/guest/templates/guests_controller.rb.tt +88 -0
- data/lib/generators/b4um/guest/templates/new.html.erb.tt +136 -0
- data/lib/generators/b4um/help/help_generator.rb +228 -0
- data/lib/generators/b4um/install/templates/b4um/sortable.css +158 -0
- data/lib/generators/b4um/install/templates/b4um.css +1 -0
- data/lib/generators/b4um/pagination/pagination_generator.rb +32 -5
- data/lib/generators/b4um/scaffold/scaffold_generator.rb +50 -0
- data/lib/generators/b4um/scaffold/templates/_form.html.erb.tt +18 -14
- data/lib/generators/b4um/search/search_generator.rb +22 -8
- data/lib/generators/b4um/sortable/sortable_generator.rb +529 -0
- data/lib/generators/b4um/sortable/templates/_sortable.html.erb.tt +40 -0
- data/lib/generators/b4um/sortable/templates/add_position_migration.rb.tt +26 -0
- data/lib/generators/b4um/sortable/templates/sort.html.erb.tt +3 -0
- data/lib/generators/b4um/sortable/templates/sortable_controller.js +166 -0
- metadata +22 -1
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/migration"
|
|
5
|
+
|
|
6
|
+
module B4um
|
|
7
|
+
module Generators
|
|
8
|
+
class AdminGenerator < Rails::Generators::Base
|
|
9
|
+
include Rails::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
desc "Adds admin user management to an existing B4UM authentication model."
|
|
14
|
+
|
|
15
|
+
argument :authentication_model,
|
|
16
|
+
type: :string,
|
|
17
|
+
required: true,
|
|
18
|
+
banner: "MODEL"
|
|
19
|
+
|
|
20
|
+
def validate_authentication_model
|
|
21
|
+
model_path = File.join(
|
|
22
|
+
destination_root,
|
|
23
|
+
"app/models",
|
|
24
|
+
"#{authentication_model_name}.rb"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return if File.exist?(model_path)
|
|
28
|
+
|
|
29
|
+
raise Thor::Error,
|
|
30
|
+
"Authentication model #{authentication_class_name} was not found. " \
|
|
31
|
+
"Expected: app/models/#{authentication_model_name}.rb"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def validate_authentication_setup
|
|
35
|
+
application_controller_path = File.join(
|
|
36
|
+
destination_root,
|
|
37
|
+
"app/controllers/application_controller.rb"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
authentication_helper =
|
|
41
|
+
"helper_method :#{current_authentication_method}, :logged_in?"
|
|
42
|
+
|
|
43
|
+
authentication_installed =
|
|
44
|
+
File.exist?(application_controller_path) &&
|
|
45
|
+
File.read(application_controller_path).include?(authentication_helper)
|
|
46
|
+
|
|
47
|
+
unless authentication_installed
|
|
48
|
+
raise Thor::Error,
|
|
49
|
+
"b4um authentication is not installed for " \
|
|
50
|
+
"#{authentication_class_name}. " \
|
|
51
|
+
"Run: bin/rails generate b4um:authentication " \
|
|
52
|
+
"#{authentication_class_name}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
application_controller =
|
|
56
|
+
File.read(application_controller_path)
|
|
57
|
+
|
|
58
|
+
current_user_assignment =
|
|
59
|
+
"@#{current_authentication_method} ||= " \
|
|
60
|
+
"#{authentication_class_name}.find_by(" \
|
|
61
|
+
"id: session[:#{authentication_model_name}_id])"
|
|
62
|
+
|
|
63
|
+
unless application_controller.include?(current_user_assignment)
|
|
64
|
+
raise Thor::Error,
|
|
65
|
+
"Could not find the current authentication method " \
|
|
66
|
+
"in app/controllers/application_controller.rb"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
sessions_controller_path = File.join(
|
|
70
|
+
destination_root,
|
|
71
|
+
"app/controllers/sessions_controller.rb"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
unless File.exist?(sessions_controller_path)
|
|
75
|
+
raise Thor::Error,
|
|
76
|
+
"SessionsController not found: " \
|
|
77
|
+
"app/controllers/sessions_controller.rb"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
sessions_controller = File.read(sessions_controller_path)
|
|
81
|
+
|
|
82
|
+
session_assignment =
|
|
83
|
+
"session[:#{authentication_model_name}_id] = " \
|
|
84
|
+
"#{authentication_model_name}.id"
|
|
85
|
+
|
|
86
|
+
return if sessions_controller.include?(session_assignment)
|
|
87
|
+
|
|
88
|
+
raise Thor::Error,
|
|
89
|
+
"Could not find the authentication session assignment " \
|
|
90
|
+
"in app/controllers/sessions_controller.rb"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def protect_admin_fields
|
|
94
|
+
controller_path = File.join(
|
|
95
|
+
destination_root,
|
|
96
|
+
"app/controllers",
|
|
97
|
+
"#{authentication_model_name.pluralize}_controller.rb"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return unless File.exist?(controller_path)
|
|
101
|
+
|
|
102
|
+
controller = File.read(controller_path)
|
|
103
|
+
|
|
104
|
+
params_method = controller.match(
|
|
105
|
+
/def #{Regexp.escape(authentication_model_name)}_params\b.*?^\s*end$/m
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return unless params_method
|
|
109
|
+
|
|
110
|
+
protected_params = params_method[0].dup
|
|
111
|
+
|
|
112
|
+
%w[admin blocked].each do |field|
|
|
113
|
+
protected_params.gsub!(
|
|
114
|
+
/:#{field}\s*,?/,
|
|
115
|
+
""
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
controller.sub!(
|
|
120
|
+
params_method[0],
|
|
121
|
+
protected_params
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
File.write(
|
|
125
|
+
controller_path,
|
|
126
|
+
controller
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def create_admin_fields_migration
|
|
131
|
+
return if admin_fields_exist?
|
|
132
|
+
|
|
133
|
+
migration_template(
|
|
134
|
+
"add_admin_fields_migration.rb.tt",
|
|
135
|
+
"db/migrate/add_admin_fields_to_#{authentication_model_name.pluralize}.rb"
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def add_admin_helper
|
|
140
|
+
controller_path = "app/controllers/application_controller.rb"
|
|
141
|
+
|
|
142
|
+
full_controller_path = File.join(
|
|
143
|
+
destination_root,
|
|
144
|
+
controller_path
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
controller = File.read(full_controller_path)
|
|
148
|
+
|
|
149
|
+
return if controller.include?("def require_admin")
|
|
150
|
+
|
|
151
|
+
class_end_position = controller.rindex(/^end\s*$/)
|
|
152
|
+
|
|
153
|
+
unless class_end_position
|
|
154
|
+
raise Thor::Error,
|
|
155
|
+
"Could not find the end of ApplicationController."
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
require_admin = <<~RUBY
|
|
159
|
+
|
|
160
|
+
def require_admin
|
|
161
|
+
return if logged_in? && #{current_authentication_method}.admin?
|
|
162
|
+
|
|
163
|
+
redirect_to root_path, alert: "Access denied."
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
RUBY
|
|
167
|
+
|
|
168
|
+
controller.insert(
|
|
169
|
+
class_end_position,
|
|
170
|
+
require_admin
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
File.write(
|
|
174
|
+
full_controller_path,
|
|
175
|
+
controller
|
|
176
|
+
)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def create_admin_base_controller
|
|
180
|
+
template(
|
|
181
|
+
"admin_base_controller.rb.tt",
|
|
182
|
+
"app/controllers/admin/base_controller.rb"
|
|
183
|
+
)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def create_admin_dashboard_controller
|
|
187
|
+
template(
|
|
188
|
+
"admin_dashboard_controller.rb.tt",
|
|
189
|
+
"app/controllers/admin/dashboard_controller.rb"
|
|
190
|
+
)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def create_admin_users_controller
|
|
194
|
+
template(
|
|
195
|
+
"admin_users_controller.rb.tt",
|
|
196
|
+
"app/controllers/admin/users_controller.rb"
|
|
197
|
+
)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def create_admin_dashboard_view
|
|
201
|
+
template(
|
|
202
|
+
"admin_dashboard.html.erb.tt",
|
|
203
|
+
"app/views/admin/dashboard/index.html.erb"
|
|
204
|
+
)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def create_admin_users_index_view
|
|
208
|
+
template(
|
|
209
|
+
"admin_users_index.html.erb.tt",
|
|
210
|
+
"app/views/admin/users/index.html.erb"
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def create_admin_creation_task
|
|
215
|
+
template(
|
|
216
|
+
"b4um_admin.rake.tt",
|
|
217
|
+
"lib/tasks/b4um_admin.rake"
|
|
218
|
+
)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def add_admin_route
|
|
222
|
+
routes_path = "config/routes.rb"
|
|
223
|
+
full_routes_path = File.join(destination_root, routes_path)
|
|
224
|
+
|
|
225
|
+
unless File.exist?(full_routes_path)
|
|
226
|
+
raise Thor::Error,
|
|
227
|
+
"Routes not found: #{routes_path}"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
admin_users_route_status =
|
|
231
|
+
upgrade_existing_admin_users_route(
|
|
232
|
+
routes_path,
|
|
233
|
+
full_routes_path
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
routes = File.read(full_routes_path)
|
|
237
|
+
|
|
238
|
+
routes_to_add = missing_admin_routes(
|
|
239
|
+
routes,
|
|
240
|
+
admin_users_route_exists:
|
|
241
|
+
admin_users_route_status == :upgraded
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return if routes_to_add.empty?
|
|
245
|
+
|
|
246
|
+
inject_into_file(
|
|
247
|
+
routes_path,
|
|
248
|
+
before: /^end\s*$/
|
|
249
|
+
) do
|
|
250
|
+
"#{routes_to_add.join("\n")}\n"
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def invalidate_blocked_sessions
|
|
255
|
+
controller_path = "app/controllers/application_controller.rb"
|
|
256
|
+
|
|
257
|
+
full_controller_path = File.join(
|
|
258
|
+
destination_root,
|
|
259
|
+
controller_path
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
controller = File.read(full_controller_path)
|
|
263
|
+
|
|
264
|
+
return if controller.include?("if @#{current_authentication_method}&.blocked?")
|
|
265
|
+
|
|
266
|
+
current_user_assignment =
|
|
267
|
+
"@#{current_authentication_method} ||= " \
|
|
268
|
+
"#{authentication_class_name}.find_by(" \
|
|
269
|
+
"id: session[:#{authentication_model_name}_id])"
|
|
270
|
+
|
|
271
|
+
unless controller.include?(current_user_assignment)
|
|
272
|
+
raise Thor::Error,
|
|
273
|
+
"Could not find the current authentication method " \
|
|
274
|
+
"in #{controller_path}"
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
replacement = <<~RUBY.chomp
|
|
278
|
+
#{current_user_assignment}
|
|
279
|
+
|
|
280
|
+
if @#{current_authentication_method}&.blocked?
|
|
281
|
+
session.delete(:#{authentication_model_name}_id)
|
|
282
|
+
@#{current_authentication_method} = nil
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
@#{current_authentication_method}
|
|
286
|
+
RUBY
|
|
287
|
+
|
|
288
|
+
gsub_file(
|
|
289
|
+
controller_path,
|
|
290
|
+
current_user_assignment,
|
|
291
|
+
replacement
|
|
292
|
+
)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def prevent_blocked_login
|
|
296
|
+
controller_path = "app/controllers/sessions_controller.rb"
|
|
297
|
+
|
|
298
|
+
full_controller_path = File.join(
|
|
299
|
+
destination_root,
|
|
300
|
+
controller_path
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
unless File.exist?(full_controller_path)
|
|
304
|
+
raise Thor::Error,
|
|
305
|
+
"SessionsController not found: #{controller_path}"
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
controller = File.read(full_controller_path)
|
|
309
|
+
|
|
310
|
+
return if controller.include?(
|
|
311
|
+
"if #{authentication_model_name}.blocked?"
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
session_assignment =
|
|
315
|
+
"session[:#{authentication_model_name}_id] = " \
|
|
316
|
+
"#{authentication_model_name}.id"
|
|
317
|
+
|
|
318
|
+
session_match = controller.match(
|
|
319
|
+
/^(\s*)#{Regexp.escape(session_assignment)}$/
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
unless session_match
|
|
323
|
+
raise Thor::Error,
|
|
324
|
+
"Could not find the authentication session assignment " \
|
|
325
|
+
"in #{controller_path}"
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
indent = session_match[1]
|
|
329
|
+
inner_indent = "#{indent} "
|
|
330
|
+
|
|
331
|
+
replacement = [
|
|
332
|
+
"#{indent}if #{authentication_model_name}.blocked?",
|
|
333
|
+
"#{inner_indent}flash.now[:alert] = \"Account is blocked.\"",
|
|
334
|
+
"#{inner_indent}render :new, status: :unprocessable_content",
|
|
335
|
+
"#{indent}else",
|
|
336
|
+
"#{inner_indent}#{session_assignment}"
|
|
337
|
+
].join("\n")
|
|
338
|
+
|
|
339
|
+
gsub_file(
|
|
340
|
+
controller_path,
|
|
341
|
+
/^#{Regexp.escape(indent)}#{Regexp.escape(session_assignment)}$/,
|
|
342
|
+
replacement
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
login_redirect =
|
|
346
|
+
'redirect_to root_path, notice: "Successfully logged in."'
|
|
347
|
+
|
|
348
|
+
controller = File.read(full_controller_path)
|
|
349
|
+
|
|
350
|
+
redirect_match = controller.match(
|
|
351
|
+
/^(\s*)#{Regexp.escape(login_redirect)}$/
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
unless redirect_match
|
|
355
|
+
raise Thor::Error,
|
|
356
|
+
"Could not find the successful login redirect " \
|
|
357
|
+
"in #{controller_path}"
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
redirect_indent = redirect_match[1]
|
|
361
|
+
|
|
362
|
+
gsub_file(
|
|
363
|
+
controller_path,
|
|
364
|
+
/^#{Regexp.escape(redirect_indent)}#{Regexp.escape(login_redirect)}$/,
|
|
365
|
+
[
|
|
366
|
+
"",
|
|
367
|
+
"#{inner_indent}#{login_redirect}",
|
|
368
|
+
"#{indent}end"
|
|
369
|
+
].join("\n")
|
|
370
|
+
)
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def self.next_migration_number(_dirname)
|
|
374
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
private
|
|
378
|
+
|
|
379
|
+
def upgrade_existing_admin_users_route(
|
|
380
|
+
_routes_path,
|
|
381
|
+
full_routes_path
|
|
382
|
+
)
|
|
383
|
+
routes = File.read(full_routes_path)
|
|
384
|
+
|
|
385
|
+
namespace_match = routes.match(
|
|
386
|
+
/^([ \t]*)namespace :admin do\s*$/
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
return :unchanged unless namespace_match
|
|
390
|
+
|
|
391
|
+
namespace_indent = namespace_match[1]
|
|
392
|
+
route_indent = "#{namespace_indent} "
|
|
393
|
+
|
|
394
|
+
namespace_start = namespace_match.end(0)
|
|
395
|
+
|
|
396
|
+
namespace_end = routes.match(
|
|
397
|
+
/^#{Regexp.escape(namespace_indent)}end\s*$/,
|
|
398
|
+
namespace_start
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
return :unchanged unless namespace_end
|
|
402
|
+
|
|
403
|
+
namespace_body = routes[
|
|
404
|
+
namespace_start...namespace_end.begin(0)
|
|
405
|
+
]
|
|
406
|
+
|
|
407
|
+
old_route_match = namespace_body.match(
|
|
408
|
+
/^#{Regexp.escape(route_indent)}#{Regexp.escape(old_admin_users_route)}$/
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
return :unchanged unless old_route_match
|
|
412
|
+
|
|
413
|
+
replacement = admin_users_resources
|
|
414
|
+
.lines
|
|
415
|
+
.map { |line| "#{route_indent}#{line}" }
|
|
416
|
+
.join
|
|
417
|
+
.chomp
|
|
418
|
+
|
|
419
|
+
route_start =
|
|
420
|
+
namespace_start + old_route_match.begin(0)
|
|
421
|
+
|
|
422
|
+
route_end =
|
|
423
|
+
namespace_start + old_route_match.end(0)
|
|
424
|
+
|
|
425
|
+
routes[route_start...route_end] = replacement
|
|
426
|
+
|
|
427
|
+
File.write(
|
|
428
|
+
full_routes_path,
|
|
429
|
+
routes
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
:upgraded
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def missing_admin_routes(
|
|
436
|
+
routes,
|
|
437
|
+
admin_users_route_exists: false
|
|
438
|
+
)
|
|
439
|
+
routes_to_add = []
|
|
440
|
+
|
|
441
|
+
routes_to_add << " #{admin_root_route}" unless routes.include?(admin_root_route)
|
|
442
|
+
|
|
443
|
+
unless admin_users_route_exists ||
|
|
444
|
+
routes.include?(admin_users_route)
|
|
445
|
+
routes_to_add << indented_admin_users_route
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
routes_to_add
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def admin_root_route
|
|
452
|
+
'get "admin", to: "admin/dashboard#index", as: :admin_root'
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def admin_users_route
|
|
456
|
+
resources = admin_users_resources
|
|
457
|
+
.lines
|
|
458
|
+
.map { |line| " #{line}" }
|
|
459
|
+
.join
|
|
460
|
+
.chomp
|
|
461
|
+
|
|
462
|
+
[
|
|
463
|
+
"namespace :admin do",
|
|
464
|
+
resources,
|
|
465
|
+
"end"
|
|
466
|
+
].join("\n")
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def admin_users_resources
|
|
470
|
+
<<~RUBY.chomp
|
|
471
|
+
resources :users, only: [:index, :destroy] do
|
|
472
|
+
member do
|
|
473
|
+
patch :block
|
|
474
|
+
patch :unblock
|
|
475
|
+
patch :grant_admin
|
|
476
|
+
patch :revoke_admin
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
RUBY
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def old_admin_users_route
|
|
483
|
+
"resources :users, only: [:index]"
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def indented_admin_users_route
|
|
487
|
+
admin_users_route
|
|
488
|
+
.lines
|
|
489
|
+
.map { |line| " #{line}" }
|
|
490
|
+
.join
|
|
491
|
+
.chomp
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
def admin_creation_fields
|
|
495
|
+
schema_path = File.join(
|
|
496
|
+
destination_root,
|
|
497
|
+
"db/schema.rb"
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
return [] unless File.exist?(schema_path)
|
|
501
|
+
|
|
502
|
+
schema = File.read(schema_path)
|
|
503
|
+
table_name = authentication_model_name.pluralize
|
|
504
|
+
|
|
505
|
+
table_match = schema.match(
|
|
506
|
+
/create_table "#{Regexp.escape(table_name)}".*?do \|t\|(.*?)^\s*end/m
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
return [] unless table_match
|
|
510
|
+
|
|
511
|
+
excluded_fields = %w[
|
|
512
|
+
id
|
|
513
|
+
email
|
|
514
|
+
password_digest
|
|
515
|
+
admin
|
|
516
|
+
blocked
|
|
517
|
+
created_at
|
|
518
|
+
updated_at
|
|
519
|
+
]
|
|
520
|
+
|
|
521
|
+
fields = table_match[1].scan(
|
|
522
|
+
/^\s*t\.(string|text)\s+"([^"]+)"/
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
fields.filter_map do |_type, field|
|
|
526
|
+
field unless excluded_fields.include?(field)
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def admin_user_display_fields
|
|
531
|
+
schema_path = File.join(
|
|
532
|
+
destination_root,
|
|
533
|
+
"db/schema.rb"
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
return ["email"] unless File.exist?(schema_path)
|
|
537
|
+
|
|
538
|
+
schema = File.read(schema_path)
|
|
539
|
+
table_name = authentication_model_name.pluralize
|
|
540
|
+
|
|
541
|
+
table_match = schema.match(
|
|
542
|
+
/create_table "#{Regexp.escape(table_name)}".*?do \|t\|(.*?)^\s*end/m
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
return ["email"] unless table_match
|
|
546
|
+
|
|
547
|
+
excluded_fields = %w[
|
|
548
|
+
id
|
|
549
|
+
admin
|
|
550
|
+
blocked
|
|
551
|
+
created_at
|
|
552
|
+
updated_at
|
|
553
|
+
]
|
|
554
|
+
|
|
555
|
+
sensitive_field_pattern = /(?:password|token|secret|digest)/i
|
|
556
|
+
|
|
557
|
+
fields = table_match[1].scan(
|
|
558
|
+
/^\s*t\.\w+\s+"([^"]+)"/
|
|
559
|
+
).flatten
|
|
560
|
+
|
|
561
|
+
fields.reject! do |field|
|
|
562
|
+
excluded_fields.include?(field) ||
|
|
563
|
+
field.match?(sensitive_field_pattern)
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
fields.empty? ? ["email"] : fields
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
def admin_user_field_label(field)
|
|
570
|
+
field.humanize
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
def authentication_class_name
|
|
574
|
+
authentication_model.to_s.classify
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def authentication_model_name
|
|
578
|
+
authentication_model.to_s.underscore
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
def current_authentication_method
|
|
582
|
+
"current_#{authentication_model_name}"
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
def admin_fields_exist?
|
|
586
|
+
admin_column_exists? && blocked_column_exists?
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
def admin_column_exists?
|
|
590
|
+
schema_table&.match?(/t\.boolean\s+"admin"/) || false
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def blocked_column_exists?
|
|
594
|
+
schema_table&.match?(/t\.boolean\s+"blocked"/) || false
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
def schema_table
|
|
598
|
+
schema_path = File.join(destination_root, "db/schema.rb")
|
|
599
|
+
|
|
600
|
+
return unless File.exist?(schema_path)
|
|
601
|
+
|
|
602
|
+
schema = File.read(schema_path)
|
|
603
|
+
|
|
604
|
+
table_name = authentication_model_name.pluralize
|
|
605
|
+
|
|
606
|
+
table_pattern = /
|
|
607
|
+
create_table\s+"#{Regexp.escape(table_name)}".*?^ end
|
|
608
|
+
/mx
|
|
609
|
+
|
|
610
|
+
schema[table_pattern]
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class AddAdminFieldsTo<%= authentication_class_name.pluralize %> < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
<% unless admin_column_exists? -%>
|
|
4
|
+
add_column :<%= authentication_model_name.pluralize %>, :admin, :boolean, default: false, null: false
|
|
5
|
+
<% end -%>
|
|
6
|
+
<% unless blocked_column_exists? -%>
|
|
7
|
+
add_column :<%= authentication_model_name.pluralize %>, :blocked, :boolean, default: false, null: false
|
|
8
|
+
<% end -%>
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<%% content_for :title, "Admin" %>
|
|
2
|
+
|
|
3
|
+
<div class="page-header">
|
|
4
|
+
<h1>Admin</h1>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="b4um-grid">
|
|
8
|
+
<section class="b4um-card b4um-card--full">
|
|
9
|
+
<h2>User management</h2>
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
Manage registered users and administrator permissions.
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<%%= link_to "Manage users",
|
|
16
|
+
admin_users_path,
|
|
17
|
+
class: "button button--primary" %>
|
|
18
|
+
</section>
|
|
19
|
+
</div>
|