cccux 0.2.1 â 0.3.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 +23 -0
- data/app/assets/stylesheets/cccux/application.css +70 -1
- data/app/controllers/cccux/ability_permissions_controller.rb +135 -24
- data/app/controllers/cccux/cccux_controller.rb +2 -2
- data/app/controllers/cccux/dashboard_controller.rb +202 -16
- data/app/helpers/cccux/authorization_helper.rb +17 -11
- data/app/models/cccux/ability.rb +1 -0
- data/app/models/cccux/ability_permission.rb +9 -0
- data/app/models/concerns/cccux/user_concern.rb +3 -0
- data/app/views/cccux/ability_permissions/new.html.erb +2 -2
- data/app/views/cccux/dashboard/model_discovery.html.erb +7 -2
- data/app/views/shared/_footer.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/lib/cccux/engine.rb +7 -6
- data/lib/cccux/version.rb +1 -1
- data/lib/cccux.rb +12 -0
- data/lib/tasks/cccux.rake +248 -157
- metadata +2 -2
|
@@ -12,6 +12,9 @@ module Cccux
|
|
|
12
12
|
scope :for_subject, ->(subject) { where(subject: subject) }
|
|
13
13
|
scope :for_action, ->(action) { where(action: action) }
|
|
14
14
|
|
|
15
|
+
# Ensure all permissions are created as active by default
|
|
16
|
+
before_create :ensure_active
|
|
17
|
+
|
|
15
18
|
def display_name
|
|
16
19
|
"#{action.humanize} #{subject}"
|
|
17
20
|
end
|
|
@@ -57,5 +60,11 @@ module Cccux
|
|
|
57
60
|
klass.column_names.include?('user_id') ||
|
|
58
61
|
klass.column_names.include?('creator_id')
|
|
59
62
|
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def ensure_active
|
|
67
|
+
self.active = true if active.nil?
|
|
68
|
+
end
|
|
60
69
|
end
|
|
61
70
|
end
|
|
@@ -9,6 +9,9 @@ module Cccux
|
|
|
9
9
|
has_many :cccux_user_roles, class_name: 'Cccux::UserRole', dependent: :destroy
|
|
10
10
|
has_many :cccux_roles, through: :cccux_user_roles, source: :role, class_name: 'Cccux::Role'
|
|
11
11
|
|
|
12
|
+
# Alias for easier access
|
|
13
|
+
alias_method :roles, :cccux_roles
|
|
14
|
+
|
|
12
15
|
# Automatically assign Basic User role to new users
|
|
13
16
|
after_create :assign_default_role
|
|
14
17
|
end
|
|
@@ -292,11 +292,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
292
292
|
function getActionType(action) {
|
|
293
293
|
const crudActions = ['read', 'create', 'update', 'destroy'];
|
|
294
294
|
if (crudActions.includes(action)) {
|
|
295
|
-
return 'CRUD';
|
|
295
|
+
return ' (CRUD)';
|
|
296
296
|
} else if (action === 'manage') {
|
|
297
297
|
return 'ALL';
|
|
298
298
|
} else {
|
|
299
|
-
return '
|
|
299
|
+
return ' (Custom)';
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
<div style="margin-bottom: 2rem;">
|
|
2
2
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
|
3
3
|
<h1 style="margin: 0; color: #495057;">Model Discovery & Permission Sync</h1>
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<div style="display: flex; gap: 0.5rem;">
|
|
5
|
+
<%= link_to "đ Refresh", cccux.clear_model_cache_path,
|
|
6
|
+
method: :post,
|
|
7
|
+
style: "background-color: #17a2b8; color: white; padding: 0.5rem 1rem; text-decoration: none; border-radius: 4px;" %>
|
|
8
|
+
<%= link_to "â Back to Dashboard", cccux.root_path,
|
|
9
|
+
style: "background-color: #6c757d; color: white; padding: 0.5rem 1rem; text-decoration: none; border-radius: 4px;" %>
|
|
10
|
+
</div>
|
|
6
11
|
</div>
|
|
7
12
|
|
|
8
13
|
<div style="background-color: #e7f3ff; border: 1px solid #b8daff; padding: 1rem; border-radius: 4px; margin-bottom: 2rem;">
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<span class="user-info">
|
|
21
21
|
Welcome, <%= current_user.respond_to?(:first_name) ? current_user.first_name : current_user.email %>
|
|
22
22
|
</span>
|
|
23
|
-
<%=
|
|
23
|
+
<%= button_to "Logout", main_app.destroy_user_session_path, method: :delete, class: "footer-link auth-link", style: "background: none; border: none; color: #007bff; text-decoration: none; padding: 5px 10px; border-radius: 4px; transition: all 0.2s ease; font-weight: 500; cursor: pointer; font: inherit;" %>
|
|
24
24
|
<% else %>
|
|
25
25
|
<%= link_to "Login", main_app.new_user_session_path, class: "footer-link auth-link" %>
|
|
26
26
|
<%= link_to "Sign Up", main_app.new_user_registration_path, class: "footer-link auth-link" %>
|
data/config/routes.rb
CHANGED
|
@@ -11,6 +11,7 @@ Cccux::Engine.routes.draw do
|
|
|
11
11
|
# Model Discovery Routes
|
|
12
12
|
get 'model-discovery', to: 'dashboard#model_discovery', as: :model_discovery
|
|
13
13
|
post 'sync-permissions', to: 'dashboard#sync_permissions', as: :sync_permissions
|
|
14
|
+
post 'clear-model-cache', to: 'dashboard#clear_model_cache', as: :clear_model_cache
|
|
14
15
|
|
|
15
16
|
# Admin CRUD routes for user management
|
|
16
17
|
resources :users do
|
data/lib/cccux/engine.rb
CHANGED
|
@@ -24,15 +24,16 @@ module Cccux
|
|
|
24
24
|
load 'tasks/cccux.rake'
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
# Configure assets for
|
|
27
|
+
# Configure assets for Propshaft (Rails 8 default)
|
|
28
28
|
initializer "cccux.assets" do |app|
|
|
29
|
-
#
|
|
30
|
-
app.config.assets.paths << root.join('app', 'assets', 'stylesheets')
|
|
31
|
-
app.config.assets.paths << root.join('app', 'assets', 'javascripts')
|
|
32
|
-
|
|
33
|
-
# For Propshaft, ensure engine assets are available
|
|
29
|
+
# For Propshaft, add the engine's asset directory to the load path
|
|
34
30
|
if defined?(Propshaft)
|
|
35
31
|
app.config.assets.paths << root.join('app', 'assets')
|
|
32
|
+
else
|
|
33
|
+
# Fallback for Sprockets if needed
|
|
34
|
+
app.config.assets.paths << root.join("app", "assets", "javascripts")
|
|
35
|
+
app.config.assets.paths << root.join("app", "assets", "stylesheets")
|
|
36
|
+
app.config.assets.paths << root.join("app", "assets", "images")
|
|
36
37
|
end
|
|
37
38
|
end
|
|
38
39
|
|
data/lib/cccux/version.rb
CHANGED
data/lib/cccux.rb
CHANGED
|
@@ -4,4 +4,16 @@ require "cancancan"
|
|
|
4
4
|
|
|
5
5
|
module Cccux
|
|
6
6
|
# Your code goes here...
|
|
7
|
+
|
|
8
|
+
# Clear model discovery cache to force refresh after new models are created
|
|
9
|
+
def self.model_discovery_cache_clear
|
|
10
|
+
# Clear any cached model lists
|
|
11
|
+
@detected_models_cache = nil
|
|
12
|
+
@module_table_patterns_cache = nil
|
|
13
|
+
|
|
14
|
+
# Force Rails to reload constants
|
|
15
|
+
Rails.application.eager_load! if Rails.application.config.eager_load
|
|
16
|
+
|
|
17
|
+
Rails.logger.info "đ CCCUX model discovery cache cleared"
|
|
18
|
+
end
|
|
7
19
|
end
|
data/lib/tasks/cccux.rake
CHANGED
|
@@ -10,55 +10,68 @@ namespace :cccux do
|
|
|
10
10
|
|
|
11
11
|
# Step 1: Ensure Devise is installed and working
|
|
12
12
|
puts "đ Step 1: Verifying Devise installation..."
|
|
13
|
-
# Check if Devise is installed and User model exists with Devise configuration
|
|
14
|
-
devise_installed = defined?(Devise)
|
|
15
|
-
user_model_exists = false
|
|
16
|
-
user_has_devise = false
|
|
17
|
-
|
|
18
|
-
if devise_installed
|
|
19
|
-
begin
|
|
20
|
-
user_class = Object.const_get('User')
|
|
21
|
-
user_model_exists = true
|
|
22
|
-
|
|
23
|
-
# Check if User model has Devise modules
|
|
24
|
-
user_has_devise = user_class.respond_to?(:devise_modules) && user_class.devise_modules.any?
|
|
25
|
-
|
|
26
|
-
# Also check if User model file contains Devise configuration as backup
|
|
27
|
-
if !user_has_devise
|
|
28
|
-
user_model_path = Rails.root.join('app', 'models', 'user.rb')
|
|
29
|
-
if File.exist?(user_model_path)
|
|
30
|
-
user_content = File.read(user_model_path)
|
|
31
|
-
user_has_devise = user_content.include?('devise :')
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
rescue NameError
|
|
35
|
-
# User model doesn't exist
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
13
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
14
|
+
# Check if Devise files exist (more reliable than checking loaded state)
|
|
15
|
+
devise_gem_in_gemfile = File.exist?(Rails.root.join('Gemfile')) &&
|
|
16
|
+
File.read(Rails.root.join('Gemfile')).include?('gem "devise"')
|
|
17
|
+
devise_initializer_exists = File.exist?(Rails.root.join('config', 'initializers', 'devise.rb'))
|
|
18
|
+
user_model_has_devise = File.exist?(Rails.root.join('app', 'models', 'user.rb')) &&
|
|
19
|
+
File.read(Rails.root.join('app', 'models', 'user.rb')).include?('devise :')
|
|
20
|
+
routes_has_devise = File.exist?(Rails.root.join('config', 'routes.rb')) &&
|
|
21
|
+
File.read(Rails.root.join('config', 'routes.rb')).include?('devise_for :users')
|
|
22
|
+
|
|
23
|
+
# Check if Devise is loaded in the current environment (optional check)
|
|
24
|
+
devise_loaded = defined?(Devise)
|
|
25
|
+
user_model_exists = defined?(User)
|
|
26
|
+
user_has_devise_methods = user_model_exists && User.respond_to?(:devise)
|
|
27
|
+
|
|
28
|
+
puts " đ Devise status check:"
|
|
29
|
+
puts " - Devise gem in Gemfile: #{devise_gem_in_gemfile ? 'â
' : 'â'}"
|
|
30
|
+
puts " - Devise initializer: #{devise_initializer_exists ? 'â
' : 'â'}"
|
|
31
|
+
puts " - User model has Devise: #{user_model_has_devise ? 'â
' : 'â'}"
|
|
32
|
+
puts " - Routes have Devise: #{routes_has_devise ? 'â
' : 'â'}"
|
|
33
|
+
puts " - Devise loaded in environment: #{devise_loaded ? 'â
' : 'â'}"
|
|
34
|
+
puts " - User model has Devise methods: #{user_has_devise_methods ? 'â
' : 'â'}"
|
|
35
|
+
|
|
36
|
+
# If Devise files exist but aren't loaded, that's normal - just continue
|
|
37
|
+
if devise_gem_in_gemfile && devise_initializer_exists && user_model_has_devise && routes_has_devise
|
|
38
|
+
if devise_loaded && user_has_devise_methods
|
|
39
|
+
puts "â
Devise is properly installed and loaded"
|
|
40
|
+
else
|
|
41
|
+
puts "â
Devise files are properly installed"
|
|
42
|
+
puts "đĄ Devise will be fully loaded after server restart"
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
puts "â Devise is not properly installed or configured."
|
|
46
|
+
puts "run the following commands to install Devise: "
|
|
42
47
|
puts " bundle add devise && rails generate devise:install && rails generate devise User && rails db:migrate"
|
|
43
|
-
puts " "
|
|
44
|
-
puts "Then re-run: rails cccux:setup"
|
|
48
|
+
puts " then run: rails cccux:setup again after Devise is installed"
|
|
45
49
|
exit 1
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
puts "â
Devise is properly installed"
|
|
49
53
|
|
|
50
|
-
# Step 2:
|
|
51
|
-
puts "đ Step 2:
|
|
54
|
+
# Step 2: Verify Devise is using default controllers
|
|
55
|
+
puts "đ Step 2: Verifying Devise configuration..."
|
|
56
|
+
if Dir.exist?(Rails.root.join('app', 'controllers', 'users'))
|
|
57
|
+
puts " â ī¸ Custom Devise controllers detected - these may cause conflicts"
|
|
58
|
+
puts " âšī¸ Using default Devise controllers is recommended for stability"
|
|
59
|
+
else
|
|
60
|
+
puts " â
Using default Devise controllers (recommended)"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Step 3: Configure routes
|
|
64
|
+
puts "đ Step 3: Configuring routes..."
|
|
52
65
|
configure_routes
|
|
53
66
|
puts "â
Routes configured"
|
|
54
67
|
|
|
55
|
-
# Step
|
|
56
|
-
puts "đ Step
|
|
68
|
+
# Step 4: Configure assets
|
|
69
|
+
puts "đ Step 4: Configuring assets..."
|
|
57
70
|
configure_assets
|
|
58
71
|
puts "â
Assets configured"
|
|
59
72
|
|
|
60
|
-
# Step
|
|
61
|
-
puts "đ Step
|
|
73
|
+
# Step 5: Run CCCUX migrations
|
|
74
|
+
puts "đ Step 5: Running CCCUX migrations..."
|
|
62
75
|
begin
|
|
63
76
|
Rake::Task['db:migrate'].invoke
|
|
64
77
|
rescue RuntimeError => e
|
|
@@ -70,39 +83,44 @@ namespace :cccux do
|
|
|
70
83
|
end
|
|
71
84
|
puts "â
CCCUX migrations completed"
|
|
72
85
|
|
|
73
|
-
# Step
|
|
74
|
-
puts "đ Step
|
|
86
|
+
# Step 6: Include CCCUX concern in User model
|
|
87
|
+
puts "đ Step 6: Adding CCCUX to User model..."
|
|
75
88
|
include_cccux_concern
|
|
76
89
|
puts "â
CCCUX concern added to User model"
|
|
77
90
|
|
|
78
|
-
# Step
|
|
79
|
-
puts "đ Step
|
|
91
|
+
# Step 7: Configure ApplicationController with CCCUX
|
|
92
|
+
puts "đ Step 7: Configuring ApplicationController with CCCUX..."
|
|
80
93
|
configure_application_controller
|
|
81
94
|
puts "â
ApplicationController configured with CCCUX"
|
|
82
95
|
|
|
83
|
-
# Step
|
|
84
|
-
puts "đ Step
|
|
96
|
+
# Step 8: Create initial roles and permissions
|
|
97
|
+
puts "đ Step 8: Creating initial roles and permissions..."
|
|
85
98
|
create_default_roles_and_permissions
|
|
86
99
|
puts "â
Default roles and permissions created"
|
|
87
100
|
|
|
88
|
-
# Step
|
|
89
|
-
puts "đ Step
|
|
101
|
+
# Step 9: Create default admin user (if no users exist)
|
|
102
|
+
puts "đ Step 9: Creating default admin user..."
|
|
90
103
|
create_default_admin_user
|
|
91
104
|
|
|
92
|
-
|
|
93
|
-
puts "đ Step
|
|
105
|
+
# Step 10: Create footer partial
|
|
106
|
+
puts "đ Step 10: Creating footer partial..."
|
|
94
107
|
create_footer_partial
|
|
95
108
|
puts "â
Footer partial created"
|
|
96
109
|
|
|
97
|
-
# Step
|
|
98
|
-
puts "đ Step
|
|
110
|
+
# Step 11: Create home controller if needed
|
|
111
|
+
puts "đ Step 11: Checking for home controller..."
|
|
99
112
|
create_home_controller
|
|
100
113
|
puts "â
Home controller check completed"
|
|
101
114
|
|
|
102
|
-
# Step
|
|
103
|
-
puts "đ Step
|
|
115
|
+
# Step 12: Verify setup
|
|
116
|
+
puts "đ Step 12: Verifying setup..."
|
|
104
117
|
verify_setup
|
|
105
118
|
|
|
119
|
+
# Step 13: Precompile assets
|
|
120
|
+
puts "đ Step 13: Precompiling assets..."
|
|
121
|
+
precompile_assets
|
|
122
|
+
puts "â
Assets precompiled"
|
|
123
|
+
|
|
106
124
|
puts ""
|
|
107
125
|
puts "đ CCCUX + Devise setup completed successfully!"
|
|
108
126
|
puts ""
|
|
@@ -224,12 +242,124 @@ namespace :cccux do
|
|
|
224
242
|
puts "â
CCCUX removed from application"
|
|
225
243
|
end
|
|
226
244
|
|
|
245
|
+
desc 'megabar:create_mega_role - Discover MegaBar models and create comprehensive permissions'
|
|
246
|
+
task 'megabar:create_mega_role' => :environment do
|
|
247
|
+
puts "đ Discovering MegaBar models and creating permissions..."
|
|
248
|
+
|
|
249
|
+
# Check if MegaBar is available
|
|
250
|
+
unless defined?(MegaBar)
|
|
251
|
+
puts "â MegaBar engine not detected"
|
|
252
|
+
puts "đĄ Make sure MegaBar is properly installed and configured"
|
|
253
|
+
exit 1
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Use the new engine discovery approach
|
|
257
|
+
megabar_models = []
|
|
258
|
+
|
|
259
|
+
begin
|
|
260
|
+
# Get all database tables that start with 'mega_bar_'
|
|
261
|
+
application_tables = ActiveRecord::Base.connection.tables.select do |table|
|
|
262
|
+
table.start_with?('mega_bar_')
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
application_tables.each do |table|
|
|
266
|
+
# Convert table name to proper namespaced model name
|
|
267
|
+
model_part = table.gsub('mega_bar_', '').singularize.camelize
|
|
268
|
+
model_name = "MegaBar::#{model_part}"
|
|
269
|
+
|
|
270
|
+
# Verify the model exists and is valid
|
|
271
|
+
begin
|
|
272
|
+
if Object.const_defined?(model_name)
|
|
273
|
+
model_class = Object.const_get(model_name)
|
|
274
|
+
if model_class.respond_to?(:table_name) &&
|
|
275
|
+
model_class.table_name == table
|
|
276
|
+
megabar_models << model_name
|
|
277
|
+
end
|
|
278
|
+
else
|
|
279
|
+
# Model constant doesn't exist yet, but table does - likely a valid model
|
|
280
|
+
megabar_models << model_name
|
|
281
|
+
end
|
|
282
|
+
rescue => e
|
|
283
|
+
# Skip if there's an error
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
rescue => e
|
|
288
|
+
puts "â Error detecting MegaBar models: #{e.message}"
|
|
289
|
+
exit 1
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
if megabar_models.empty?
|
|
293
|
+
puts "â ī¸ No MegaBar models found"
|
|
294
|
+
puts "đĄ Make sure MegaBar is properly set up and models exist"
|
|
295
|
+
exit 1
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
puts "đ Found #{megabar_models.count} MegaBar models:"
|
|
299
|
+
megabar_models.each { |model| puts " - #{model}" }
|
|
300
|
+
|
|
301
|
+
# Create "Mega Role" if it doesn't exist
|
|
302
|
+
mega_role = Cccux::Role.find_or_create_by(name: 'Mega Role') do |role|
|
|
303
|
+
role.description = 'Global permissions for all MegaBar models'
|
|
304
|
+
role.active = true
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
if mega_role.persisted? && !mega_role.previously_persisted?
|
|
308
|
+
puts "â
Created 'Mega Role'"
|
|
309
|
+
puts "đĄ Visit /cccux/users/ to assign users to the 'Mega Role'"
|
|
310
|
+
else
|
|
311
|
+
puts "âšī¸ 'Mega Role' already exists"
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Create CRUD permissions for each MegaBar model
|
|
315
|
+
actions = %w[create read update destroy]
|
|
316
|
+
permissions_created = 0
|
|
317
|
+
|
|
318
|
+
megabar_models.each do |model_name|
|
|
319
|
+
actions.each do |action|
|
|
320
|
+
permission = Cccux::AbilityPermission.find_or_create_by(
|
|
321
|
+
action: action,
|
|
322
|
+
subject: model_name
|
|
323
|
+
) do |p|
|
|
324
|
+
p.description = "#{action.capitalize} #{model_name.pluralize.downcase}"
|
|
325
|
+
p.active = true
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
if permission.persisted? && !permission.previously_persisted?
|
|
329
|
+
permissions_created += 1
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Assign all permissions to the Mega Role
|
|
335
|
+
assigned_permissions = 0
|
|
336
|
+
Cccux::AbilityPermission.where(subject: megabar_models).each do |permission|
|
|
337
|
+
role_ability = Cccux::RoleAbility.find_or_create_by(
|
|
338
|
+
role: mega_role,
|
|
339
|
+
ability_permission: permission
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
if role_ability.persisted? && !role_ability.previously_persisted?
|
|
343
|
+
assigned_permissions += 1
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
puts "â
Created #{permissions_created} permissions for MegaBar models"
|
|
348
|
+
puts "â
Assigned #{assigned_permissions} permissions to 'Mega Role'"
|
|
349
|
+
puts ""
|
|
350
|
+
puts "đ MegaBar permissions setup completed!"
|
|
351
|
+
puts "đĄ Users with 'Mega Role' will have full access to all MegaBar models"
|
|
352
|
+
end
|
|
353
|
+
|
|
227
354
|
private
|
|
228
355
|
|
|
229
356
|
def configure_routes
|
|
230
357
|
routes_path = Rails.root.join('config/routes.rb')
|
|
231
358
|
routes_content = File.read(routes_path)
|
|
232
359
|
|
|
360
|
+
# Check if Devise controllers exist
|
|
361
|
+
devise_controllers_exist = Dir.exist?(Rails.root.join('app', 'controllers', 'users'))
|
|
362
|
+
|
|
233
363
|
# Ensure devise_for :users is before engine mount
|
|
234
364
|
unless routes_content.include?('devise_for :users')
|
|
235
365
|
puts " â Adding devise_for :users to routes..."
|
|
@@ -238,6 +368,12 @@ namespace :cccux do
|
|
|
238
368
|
routes_content = File.read(routes_path)
|
|
239
369
|
end
|
|
240
370
|
|
|
371
|
+
# Ensure routes use default Devise controllers (recommended for stability)
|
|
372
|
+
if devise_controllers_exist
|
|
373
|
+
puts " â ī¸ Custom Devise controllers detected - consider removing them for stability"
|
|
374
|
+
puts " âšī¸ Routes will use default Devise controllers"
|
|
375
|
+
end
|
|
376
|
+
|
|
241
377
|
# Add engine mount if not present
|
|
242
378
|
unless routes_content.include?('mount Cccux::Engine')
|
|
243
379
|
puts " â Adding CCCUX engine mount to routes..."
|
|
@@ -250,40 +386,9 @@ namespace :cccux do
|
|
|
250
386
|
end
|
|
251
387
|
|
|
252
388
|
def configure_assets
|
|
253
|
-
#
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
css_content = File.read(css_path)
|
|
257
|
-
|
|
258
|
-
# Check if we're using Propshaft or Sprockets
|
|
259
|
-
if defined?(Propshaft)
|
|
260
|
-
# For Propshaft, copy the actual CSS content since it doesn't process @import
|
|
261
|
-
unless css_content.include?('CCCUX Engine Styles')
|
|
262
|
-
# Read the CCCUX CSS content
|
|
263
|
-
cccux_css_path = File.join(File.dirname(__FILE__), '..', '..', 'app', 'assets', 'stylesheets', 'cccux', 'application.css')
|
|
264
|
-
if File.exist?(cccux_css_path)
|
|
265
|
-
cccux_css_content = File.read(cccux_css_path)
|
|
266
|
-
# Extract just the CSS rules, not the manifest comments
|
|
267
|
-
css_rules = cccux_css_content.split('*/').last.strip if cccux_css_content.include?('*/')
|
|
268
|
-
css_rules ||= cccux_css_content
|
|
269
|
-
|
|
270
|
-
File.open(css_path, 'a') do |f|
|
|
271
|
-
f.puts "\n\n/* CCCUX Engine Styles - Added by CCCUX setup */"
|
|
272
|
-
f.puts css_rules
|
|
273
|
-
end
|
|
274
|
-
puts " â
Added CCCUX CSS content to application.css (Propshaft)"
|
|
275
|
-
else
|
|
276
|
-
puts " â ī¸ Could not find CCCUX CSS file at #{cccux_css_path}"
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
else
|
|
280
|
-
# Sprockets uses *= require syntax
|
|
281
|
-
unless css_content.include?('cccux/application')
|
|
282
|
-
File.open(css_path, 'a') { |f| f.puts "/*\n *= require cccux/application\n */" }
|
|
283
|
-
puts " â
Added CCCUX CSS to application.css (Sprockets)"
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end
|
|
389
|
+
# Note: CCCUX styles are now loaded via the engine's asset pipeline
|
|
390
|
+
# No need to copy styles to host app's application.css
|
|
391
|
+
puts " âšī¸ CCCUX styles will be loaded via engine asset pipeline"
|
|
287
392
|
|
|
288
393
|
# Add JavaScript assets (if using legacy asset pipeline)
|
|
289
394
|
js_path = Rails.root.join('app/assets/javascripts/application.js')
|
|
@@ -580,10 +685,10 @@ namespace :cccux do
|
|
|
580
685
|
|
|
581
686
|
footer_path = shared_dir.join('_footer.html.erb')
|
|
582
687
|
|
|
583
|
-
# Create footer content
|
|
688
|
+
# Create footer content - No inline styles, uses CCCUX engine CSS
|
|
584
689
|
footer_content = <<~ERB
|
|
585
|
-
<!-- CCCUX Footer -
|
|
586
|
-
<footer class="cccux-footer"
|
|
690
|
+
<!-- CCCUX Footer - Styles loaded from CCCUX engine -->
|
|
691
|
+
<footer class="cccux-footer">
|
|
587
692
|
<div class="container">
|
|
588
693
|
<div class="row">
|
|
589
694
|
<div class="col-md-6">
|
|
@@ -591,7 +696,7 @@ namespace :cccux do
|
|
|
591
696
|
<a href="<%= main_app.root_path %>" class="footer-link">đ Home</a>
|
|
592
697
|
<% if user_signed_in? && current_user.has_role?('Role Manager') %>
|
|
593
698
|
<span class="footer-separator">|</span>
|
|
594
|
-
<a href="
|
|
699
|
+
<a href="/cccux" class="footer-link">âī¸ CCCUX Admin</a>
|
|
595
700
|
<% end %>
|
|
596
701
|
</nav>
|
|
597
702
|
</div>
|
|
@@ -600,10 +705,7 @@ namespace :cccux do
|
|
|
600
705
|
<span class="user-info">
|
|
601
706
|
đ¤ <strong><%= current_user.email %></strong>
|
|
602
707
|
<span class="footer-separator">|</span>
|
|
603
|
-
<%=
|
|
604
|
-
method: :delete,
|
|
605
|
-
class: "footer-link",
|
|
606
|
-
data: { turbo_method: :delete } %>
|
|
708
|
+
<%= button_to "Logout", main_app.destroy_user_session_path, method: :delete, class: "footer-link auth-link", style: "background: none; border: none; color: #007bff; text-decoration: none; padding: 5px 10px; border-radius: 4px; transition: all 0.2s ease; font-weight: 500; cursor: pointer; font: inherit;" %>
|
|
607
709
|
</span>
|
|
608
710
|
<% else %>
|
|
609
711
|
<span class="auth-links">
|
|
@@ -616,67 +718,17 @@ namespace :cccux do
|
|
|
616
718
|
</div>
|
|
617
719
|
</div>
|
|
618
720
|
</footer>
|
|
619
|
-
|
|
620
|
-
<style>
|
|
621
|
-
.cccux-footer {
|
|
622
|
-
font-size: 0.9rem;
|
|
623
|
-
color: #6c757d;
|
|
624
|
-
}
|
|
625
|
-
.cccux-footer .footer-link {
|
|
626
|
-
color: #007bff;
|
|
627
|
-
text-decoration: none;
|
|
628
|
-
margin: 0 0.5rem;
|
|
629
|
-
}
|
|
630
|
-
.cccux-footer .footer-link:hover {
|
|
631
|
-
color: #0056b3;
|
|
632
|
-
text-decoration: underline;
|
|
633
|
-
}
|
|
634
|
-
.cccux-footer .footer-separator {
|
|
635
|
-
color: #dee2e6;
|
|
636
|
-
margin: 0 0.25rem;
|
|
637
|
-
}
|
|
638
|
-
.cccux-footer .user-info,
|
|
639
|
-
.cccux-footer .auth-links {
|
|
640
|
-
font-size: 0.85rem;
|
|
641
|
-
}
|
|
642
|
-
.cccux-footer .container {
|
|
643
|
-
max-width: 1200px;
|
|
644
|
-
margin: 0 auto;
|
|
645
|
-
padding: 0 1rem;
|
|
646
|
-
}
|
|
647
|
-
.cccux-footer .row {
|
|
648
|
-
display: flex;
|
|
649
|
-
justify-content: space-between;
|
|
650
|
-
align-items: center;
|
|
651
|
-
flex-wrap: wrap;
|
|
652
|
-
}
|
|
653
|
-
.cccux-footer .col-md-6 {
|
|
654
|
-
flex: 1;
|
|
655
|
-
min-width: 300px;
|
|
656
|
-
}
|
|
657
|
-
.cccux-footer .text-end {
|
|
658
|
-
text-align: right;
|
|
659
|
-
}
|
|
660
|
-
@media (max-width: 768px) {
|
|
661
|
-
.cccux-footer .row {
|
|
662
|
-
flex-direction: column;
|
|
663
|
-
gap: 0.5rem;
|
|
664
|
-
}
|
|
665
|
-
.cccux-footer .col-md-6 {
|
|
666
|
-
text-align: center;
|
|
667
|
-
}
|
|
668
|
-
.cccux-footer .text-end {
|
|
669
|
-
text-align: center;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
</style>
|
|
673
721
|
ERB
|
|
674
722
|
|
|
675
723
|
# Write the footer partial
|
|
676
724
|
File.write(footer_path, footer_content)
|
|
677
|
-
puts "
|
|
725
|
+
puts "â
Created footer partial at #{footer_path}"
|
|
678
726
|
|
|
679
|
-
#
|
|
727
|
+
# Include footer in application layout
|
|
728
|
+
include_footer_in_layout
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
def include_footer_in_layout
|
|
680
732
|
layout_path = Rails.root.join('app', 'views', 'layouts', 'application.html.erb')
|
|
681
733
|
if File.exist?(layout_path)
|
|
682
734
|
layout_content = File.read(layout_path)
|
|
@@ -690,35 +742,74 @@ namespace :cccux do
|
|
|
690
742
|
"\\1 <%= render 'shared/footer' %>\n\\1</body>"
|
|
691
743
|
)
|
|
692
744
|
File.write(layout_path, updated_content)
|
|
693
|
-
puts "
|
|
745
|
+
puts "â
Added footer to application layout"
|
|
694
746
|
else
|
|
695
|
-
puts "
|
|
747
|
+
puts "â ī¸ Could not find </body> tag in application layout - please manually add: <%= render 'shared/footer' %>"
|
|
696
748
|
end
|
|
697
749
|
else
|
|
698
|
-
puts "
|
|
750
|
+
puts "âšī¸ Footer already included in application layout"
|
|
699
751
|
end
|
|
700
752
|
else
|
|
701
|
-
puts "
|
|
753
|
+
puts "â ī¸ Application layout not found - please manually add: <%= render 'shared/footer' %>"
|
|
702
754
|
end
|
|
703
755
|
end
|
|
704
756
|
|
|
705
757
|
def verify_setup
|
|
706
758
|
# Test that User model has CCCUX methods
|
|
759
|
+
# First, try to reload the User model file to pick up the concern
|
|
760
|
+
begin
|
|
761
|
+
load Rails.root.join('app', 'models', 'user.rb')
|
|
762
|
+
rescue => e
|
|
763
|
+
puts " â ī¸ Could not reload User model: #{e.message}"
|
|
764
|
+
end
|
|
765
|
+
|
|
707
766
|
user = User.new
|
|
708
767
|
unless user.respond_to?(:has_role?)
|
|
709
768
|
puts "â User model missing CCCUX methods"
|
|
769
|
+
puts " đĄ This sometimes happens on the first run. Try running 'rails cccux:setup' again."
|
|
770
|
+
puts " đ§ The concern was added to the User model file, but Rails needs to reload it."
|
|
710
771
|
exit 1
|
|
711
772
|
end
|
|
712
773
|
|
|
713
774
|
puts "â
CCCUX methods available on User model"
|
|
714
775
|
|
|
715
|
-
#
|
|
776
|
+
# Check if Devise files exist (more reliable than testing routes in rake context)
|
|
777
|
+
devise_initializer_exists = File.exist?(Rails.root.join('config', 'initializers', 'devise.rb'))
|
|
778
|
+
user_model_has_devise = File.exist?(Rails.root.join('app', 'models', 'user.rb')) &&
|
|
779
|
+
File.read(Rails.root.join('app', 'models', 'user.rb')).include?('devise :')
|
|
780
|
+
routes_has_devise = File.exist?(Rails.root.join('config', 'routes.rb')) &&
|
|
781
|
+
File.read(Rails.root.join('config', 'routes.rb')).include?('devise_for :users')
|
|
782
|
+
|
|
783
|
+
puts " đ Devise file verification:"
|
|
784
|
+
puts " - Devise initializer: #{devise_initializer_exists ? 'â
' : 'â'}"
|
|
785
|
+
puts " - User model has Devise: #{user_model_has_devise ? 'â
' : 'â'}"
|
|
786
|
+
puts " - Routes have Devise: #{routes_has_devise ? 'â
' : 'â'}"
|
|
787
|
+
|
|
788
|
+
if devise_initializer_exists && user_model_has_devise && routes_has_devise
|
|
789
|
+
puts "â
Devise files properly configured"
|
|
790
|
+
puts "đĄ Devise routes will be available after server restart"
|
|
791
|
+
else
|
|
792
|
+
puts "â ī¸ Some Devise files may be missing or incomplete"
|
|
793
|
+
puts "đĄ This is normal if Devise was just installed - restart your server to complete setup"
|
|
794
|
+
end
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
def precompile_assets
|
|
798
|
+
puts " đ§ Precompiling CCCUX assets..."
|
|
799
|
+
|
|
716
800
|
begin
|
|
717
|
-
|
|
718
|
-
|
|
801
|
+
# Run assets:precompile task
|
|
802
|
+
Rake::Task['assets:precompile'].invoke
|
|
803
|
+
puts " â
Assets precompiled successfully"
|
|
804
|
+
rescue RuntimeError => e
|
|
805
|
+
if e.message.include?("Don't know how to build task 'assets:precompile'")
|
|
806
|
+
puts " â ī¸ Assets precompile task not available (this is normal in some contexts)"
|
|
807
|
+
puts " âšī¸ Assets will be compiled automatically when the server starts"
|
|
808
|
+
else
|
|
809
|
+
puts " â Error precompiling assets: #{e.message}"
|
|
810
|
+
end
|
|
719
811
|
rescue => e
|
|
720
|
-
puts "â
|
|
721
|
-
exit 1
|
|
812
|
+
puts " â Unexpected error during asset precompilation: #{e.message}"
|
|
722
813
|
end
|
|
723
814
|
end
|
|
724
815
|
end
|