cccux 0.1.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 +7 -0
- data/CHANGELOG.md +67 -0
- data/MIT-LICENSE +20 -0
- data/README.md +382 -0
- data/Rakefile +8 -0
- data/app/assets/config/cccux_manifest.js +1 -0
- data/app/assets/stylesheets/cccux/application.css +102 -0
- data/app/controllers/cccux/ability_permissions_controller.rb +271 -0
- data/app/controllers/cccux/application_controller.rb +37 -0
- data/app/controllers/cccux/authorization_controller.rb +10 -0
- data/app/controllers/cccux/cccux_controller.rb +64 -0
- data/app/controllers/cccux/dashboard_controller.rb +172 -0
- data/app/controllers/cccux/home_controller.rb +19 -0
- data/app/controllers/cccux/roles_controller.rb +290 -0
- data/app/controllers/cccux/simple_controller.rb +7 -0
- data/app/controllers/cccux/users_controller.rb +112 -0
- data/app/controllers/concerns/cccux/application_controller_concern.rb +32 -0
- data/app/helpers/cccux/application_helper.rb +4 -0
- data/app/helpers/cccux/authorization_helper.rb +228 -0
- data/app/jobs/cccux/application_job.rb +4 -0
- data/app/mailers/cccux/application_mailer.rb +6 -0
- data/app/models/cccux/ability.rb +142 -0
- data/app/models/cccux/ability_permission.rb +61 -0
- data/app/models/cccux/application_record.rb +5 -0
- data/app/models/cccux/role.rb +90 -0
- data/app/models/cccux/role_ability.rb +49 -0
- data/app/models/cccux/user_role.rb +42 -0
- data/app/models/concerns/cccux/authorizable.rb +25 -0
- data/app/models/concerns/cccux/scoped_ownership.rb +183 -0
- data/app/models/concerns/cccux/user_concern.rb +87 -0
- data/app/views/cccux/ability_permissions/edit.html.erb +58 -0
- data/app/views/cccux/ability_permissions/index.html.erb +108 -0
- data/app/views/cccux/ability_permissions/new.html.erb +308 -0
- data/app/views/cccux/dashboard/index.html.erb +69 -0
- data/app/views/cccux/dashboard/model_discovery.html.erb +148 -0
- data/app/views/cccux/home/index.html.erb +42 -0
- data/app/views/cccux/roles/_flash.html.erb +10 -0
- data/app/views/cccux/roles/_form.html.erb +78 -0
- data/app/views/cccux/roles/_role.html.erb +67 -0
- data/app/views/cccux/roles/edit.html.erb +317 -0
- data/app/views/cccux/roles/index.html.erb +51 -0
- data/app/views/cccux/roles/new.html.erb +3 -0
- data/app/views/cccux/roles/show.html.erb +99 -0
- data/app/views/cccux/users/edit.html.erb +117 -0
- data/app/views/cccux/users/index.html.erb +99 -0
- data/app/views/cccux/users/new.html.erb +94 -0
- data/app/views/cccux/users/show.html.erb +138 -0
- data/app/views/layouts/cccux/admin.html.erb +168 -0
- data/app/views/layouts/cccux/application.html.erb +17 -0
- data/app/views/shared/_footer.html.erb +101 -0
- data/config/routes.rb +63 -0
- data/db/migrate/20250626194001_create_cccux_roles.rb +15 -0
- data/db/migrate/20250626194007_create_cccux_ability_permissions.rb +18 -0
- data/db/migrate/20250626194011_create_cccux_user_roles.rb +13 -0
- data/db/migrate/20250626194016_create_cccux_role_abilities.rb +10 -0
- data/db/migrate/20250627170611_add_owned_to_cccux_role_abilities.rb +9 -0
- data/db/migrate/20250705193709_add_context_to_cccux_role_abilities.rb +9 -0
- data/db/migrate/20250706214415_add_ownership_configuration_to_role_abilities.rb +21 -0
- data/db/seeds.rb +136 -0
- data/lib/cccux/engine.rb +50 -0
- data/lib/cccux/version.rb +3 -0
- data/lib/cccux.rb +7 -0
- data/lib/tasks/cccux.rake +703 -0
- data/lib/tasks/view_helpers.rake +274 -0
- metadata +188 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
# CCCUX Engine Tasks
|
|
2
|
+
# Clean, consolidated setup and management tasks for the CCCUX authorization engine
|
|
3
|
+
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
namespace :cccux do
|
|
7
|
+
desc 'setup - Complete setup for CCCUX with Devise integration'
|
|
8
|
+
task setup: :environment do
|
|
9
|
+
puts "đ Starting CCCUX + Devise setup..."
|
|
10
|
+
|
|
11
|
+
# Step 1: Ensure Devise is installed and working
|
|
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
|
+
|
|
39
|
+
unless devise_installed && user_model_exists && user_has_devise
|
|
40
|
+
puts "â Devise is not properly installed or configured. Please run the following command first:"
|
|
41
|
+
puts " "
|
|
42
|
+
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"
|
|
45
|
+
exit 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
puts "â
Devise is properly installed"
|
|
49
|
+
|
|
50
|
+
# Step 2: Configure routes
|
|
51
|
+
puts "đ Step 2: Configuring routes..."
|
|
52
|
+
configure_routes
|
|
53
|
+
puts "â
Routes configured"
|
|
54
|
+
|
|
55
|
+
# Step 3: Configure assets
|
|
56
|
+
puts "đ Step 3: Configuring assets..."
|
|
57
|
+
configure_assets
|
|
58
|
+
puts "â
Assets configured"
|
|
59
|
+
|
|
60
|
+
# Step 4: Run CCCUX migrations
|
|
61
|
+
puts "đ Step 4: Running CCCUX migrations..."
|
|
62
|
+
Rake::Task['db:migrate'].invoke
|
|
63
|
+
puts "â
CCCUX migrations completed"
|
|
64
|
+
|
|
65
|
+
# Step 5: Include CCCUX concern in User model
|
|
66
|
+
puts "đ Step 5: Adding CCCUX to User model..."
|
|
67
|
+
include_cccux_concern
|
|
68
|
+
puts "â
CCCUX concern added to User model"
|
|
69
|
+
|
|
70
|
+
# Step 5.5: Configure ApplicationController with CCCUX
|
|
71
|
+
puts "đ Step 5.5: Configuring ApplicationController with CCCUX..."
|
|
72
|
+
configure_application_controller
|
|
73
|
+
puts "â
ApplicationController configured with CCCUX"
|
|
74
|
+
|
|
75
|
+
# Step 6: Create initial roles and permissions
|
|
76
|
+
puts "đ Step 6: Creating initial roles and permissions..."
|
|
77
|
+
create_default_roles_and_permissions
|
|
78
|
+
puts "â
Default roles and permissions created"
|
|
79
|
+
|
|
80
|
+
# Step 7: Create default admin user (if no users exist)
|
|
81
|
+
puts "đ Step 7: Creating default admin user..."
|
|
82
|
+
create_default_admin_user
|
|
83
|
+
|
|
84
|
+
# Step 8: Create footer partial
|
|
85
|
+
puts "đ Step 8: Creating footer partial..."
|
|
86
|
+
create_footer_partial
|
|
87
|
+
puts "â
Footer partial created"
|
|
88
|
+
|
|
89
|
+
# Step 9: Create home controller if needed
|
|
90
|
+
puts "đ Step 9: Checking for home controller..."
|
|
91
|
+
create_home_controller
|
|
92
|
+
puts "â
Home controller check completed"
|
|
93
|
+
|
|
94
|
+
# Step 10: Verify setup
|
|
95
|
+
puts "đ Step 10: Verifying setup..."
|
|
96
|
+
verify_setup
|
|
97
|
+
|
|
98
|
+
puts ""
|
|
99
|
+
puts "đ CCCUX + Devise setup completed successfully!"
|
|
100
|
+
puts ""
|
|
101
|
+
puts "đ Next steps:"
|
|
102
|
+
puts " 1. Start your Rails server: rails server"
|
|
103
|
+
puts " 2. Visit http://localhost:3000/cccux to access the admin interface"
|
|
104
|
+
puts " 3. Sign in with your admin account"
|
|
105
|
+
puts ""
|
|
106
|
+
puts "đ Need help? Check the CCCUX documentation or README"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
desc 'test - Test CCCUX + Devise integration'
|
|
110
|
+
task test: :environment do
|
|
111
|
+
puts "đ§Ē Testing CCCUX + Devise integration..."
|
|
112
|
+
|
|
113
|
+
# Test User model
|
|
114
|
+
user = User.new(email: 'test@example.com', password: 'password123')
|
|
115
|
+
puts "â
User model accepts CCCUX methods" if user.respond_to?(:has_role?)
|
|
116
|
+
|
|
117
|
+
# Test roles
|
|
118
|
+
role_manager = Cccux::Role.find_by(name: 'Role Manager')
|
|
119
|
+
basic_user = Cccux::Role.find_by(name: 'Basic User')
|
|
120
|
+
guest = Cccux::Role.find_by(name: 'Guest')
|
|
121
|
+
puts "â
Role Manager role exists" if role_manager
|
|
122
|
+
puts "â
Basic User role exists" if basic_user
|
|
123
|
+
puts "â
Guest role exists" if guest
|
|
124
|
+
|
|
125
|
+
# Test permissions
|
|
126
|
+
permissions = Cccux::AbilityPermission.count
|
|
127
|
+
puts "â
Found #{permissions} permissions"
|
|
128
|
+
|
|
129
|
+
puts "đ All tests passed!"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
desc 'status - Show CCCUX integration status'
|
|
133
|
+
task status: :environment do
|
|
134
|
+
puts "đ CCCUX Integration Status"
|
|
135
|
+
puts "=" * 50
|
|
136
|
+
|
|
137
|
+
# Check routes
|
|
138
|
+
routes_content = File.read('config/routes.rb')
|
|
139
|
+
routes_configured = routes_content.include?('mount Cccux::Engine')
|
|
140
|
+
puts "Routes: #{routes_configured ? 'â
Configured' : 'â Not configured'}"
|
|
141
|
+
|
|
142
|
+
# Check User model
|
|
143
|
+
user_model_path = Rails.root.join('app', 'models', 'user.rb')
|
|
144
|
+
if File.exist?(user_model_path)
|
|
145
|
+
user_content = File.read(user_model_path)
|
|
146
|
+
cccux_included = user_content.include?('Cccux::UserConcern')
|
|
147
|
+
devise_configured = user_content.include?('devise :')
|
|
148
|
+
puts "User Model: #{cccux_included && devise_configured ? 'â
Configured' : 'â Not configured'}"
|
|
149
|
+
else
|
|
150
|
+
puts "User Model: â Not found"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Check ApplicationController
|
|
154
|
+
app_controller_path = Rails.root.join('app', 'controllers', 'application_controller.rb')
|
|
155
|
+
if File.exist?(app_controller_path)
|
|
156
|
+
app_controller_content = File.read(app_controller_path)
|
|
157
|
+
cccux_configured = app_controller_content.include?('Cccux::ApplicationControllerConcern') ||
|
|
158
|
+
app_controller_content.include?('include CanCan::ControllerAdditions')
|
|
159
|
+
puts "Controller: #{cccux_configured ? 'â
CCCUX authorization configured' : 'â Not configured'}"
|
|
160
|
+
else
|
|
161
|
+
puts "Controller: â ApplicationController not found"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Check database
|
|
165
|
+
begin
|
|
166
|
+
if defined?(User)
|
|
167
|
+
user_count = User.count
|
|
168
|
+
role_count = Cccux::Role.count
|
|
169
|
+
permission_count = Cccux::AbilityPermission.count
|
|
170
|
+
puts "Database: â
Connected (#{user_count} users, #{role_count} roles, #{permission_count} permissions)"
|
|
171
|
+
else
|
|
172
|
+
puts "Database: â User model not loaded"
|
|
173
|
+
end
|
|
174
|
+
rescue => e
|
|
175
|
+
puts "Database: â Error: #{e.message}"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
puts ""
|
|
179
|
+
if routes_configured
|
|
180
|
+
puts "đ CCCUX appears to be properly configured!"
|
|
181
|
+
puts " Visit /cccux to access the admin interface"
|
|
182
|
+
else
|
|
183
|
+
puts "â ī¸ CCCUX needs configuration. Run: rails cccux:setup"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
desc 'reset - Remove CCCUX from host application'
|
|
188
|
+
task reset: :environment do
|
|
189
|
+
puts "đī¸ Removing CCCUX Authorization Engine..."
|
|
190
|
+
|
|
191
|
+
# Remove migrations
|
|
192
|
+
puts "Removing migrations..."
|
|
193
|
+
migration_files = Dir.glob(Rails.root.join('db/migrate/*_cccux_*.rb'))
|
|
194
|
+
migration_files.each { |file| File.delete(file) }
|
|
195
|
+
|
|
196
|
+
# Drop tables
|
|
197
|
+
puts "Dropping CCCUX tables..."
|
|
198
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS cccux_role_abilities")
|
|
199
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS cccux_user_roles")
|
|
200
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS cccux_ability_permissions")
|
|
201
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS cccux_roles")
|
|
202
|
+
|
|
203
|
+
puts "â
CCCUX removed from application"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
private
|
|
207
|
+
|
|
208
|
+
def configure_routes
|
|
209
|
+
routes_path = Rails.root.join('config/routes.rb')
|
|
210
|
+
routes_content = File.read(routes_path)
|
|
211
|
+
|
|
212
|
+
# Ensure devise_for :users is before engine mount
|
|
213
|
+
unless routes_content.include?('devise_for :users')
|
|
214
|
+
puts " â Adding devise_for :users to routes..."
|
|
215
|
+
new_content = "Rails.application.routes.draw do\n devise_for :users\n\n" + routes_content.lines[1..-1].join
|
|
216
|
+
File.write(routes_path, new_content)
|
|
217
|
+
routes_content = File.read(routes_path)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Add engine mount if not present
|
|
221
|
+
unless routes_content.include?('mount Cccux::Engine')
|
|
222
|
+
puts " â Adding CCCUX engine mount to routes..."
|
|
223
|
+
new_content = routes_content.gsub(
|
|
224
|
+
/(Rails\.application\.routes\.draw do)/,
|
|
225
|
+
"\\1\n\n ##### CCCUX BEGIN #####\n mount Cccux::Engine, at: '/cccux'\n ##### CCCUX END #####"
|
|
226
|
+
)
|
|
227
|
+
File.write(routes_path, new_content)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def configure_assets
|
|
232
|
+
# Add CSS assets
|
|
233
|
+
css_path = Rails.root.join('app/assets/stylesheets/application.css')
|
|
234
|
+
if File.exist?(css_path)
|
|
235
|
+
css_content = File.read(css_path)
|
|
236
|
+
|
|
237
|
+
# Check if we're using Propshaft or Sprockets
|
|
238
|
+
if defined?(Propshaft)
|
|
239
|
+
# For Propshaft, copy the actual CSS content since it doesn't process @import
|
|
240
|
+
unless css_content.include?('CCCUX Engine Styles')
|
|
241
|
+
# Read the CCCUX CSS content
|
|
242
|
+
cccux_css_path = File.join(File.dirname(__FILE__), '..', '..', 'app', 'assets', 'stylesheets', 'cccux', 'application.css')
|
|
243
|
+
if File.exist?(cccux_css_path)
|
|
244
|
+
cccux_css_content = File.read(cccux_css_path)
|
|
245
|
+
# Extract just the CSS rules, not the manifest comments
|
|
246
|
+
css_rules = cccux_css_content.split('*/').last.strip if cccux_css_content.include?('*/')
|
|
247
|
+
css_rules ||= cccux_css_content
|
|
248
|
+
|
|
249
|
+
File.open(css_path, 'a') do |f|
|
|
250
|
+
f.puts "\n\n/* CCCUX Engine Styles - Added by CCCUX setup */"
|
|
251
|
+
f.puts css_rules
|
|
252
|
+
end
|
|
253
|
+
puts " â
Added CCCUX CSS content to application.css (Propshaft)"
|
|
254
|
+
else
|
|
255
|
+
puts " â ī¸ Could not find CCCUX CSS file at #{cccux_css_path}"
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
else
|
|
259
|
+
# Sprockets uses *= require syntax
|
|
260
|
+
unless css_content.include?('cccux/application')
|
|
261
|
+
File.open(css_path, 'a') { |f| f.puts "/*\n *= require cccux/application\n */" }
|
|
262
|
+
puts " â
Added CCCUX CSS to application.css (Sprockets)"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Add JavaScript assets (if using legacy asset pipeline)
|
|
268
|
+
js_path = Rails.root.join('app/assets/javascripts/application.js')
|
|
269
|
+
if File.exist?(js_path)
|
|
270
|
+
js_content = File.read(js_path)
|
|
271
|
+
unless js_content.include?('cccux/application')
|
|
272
|
+
File.open(js_path, 'a') { |f| f.puts "//= require cccux/application" }
|
|
273
|
+
puts " â
Added CCCUX JavaScript to application.js"
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def include_cccux_concern
|
|
279
|
+
user_model_path = Rails.root.join('app', 'models', 'user.rb')
|
|
280
|
+
user_content = File.read(user_model_path)
|
|
281
|
+
|
|
282
|
+
unless user_content.include?('Cccux::UserConcern')
|
|
283
|
+
updated_content = user_content.gsub(
|
|
284
|
+
/class User < ApplicationRecord/,
|
|
285
|
+
"class User < ApplicationRecord\n include Cccux::UserConcern"
|
|
286
|
+
)
|
|
287
|
+
File.write(user_model_path, updated_content)
|
|
288
|
+
puts " â
Added Cccux::UserConcern to User model"
|
|
289
|
+
else
|
|
290
|
+
puts " âšī¸ User model already includes Cccux::UserConcern"
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def configure_application_controller
|
|
295
|
+
application_controller_path = Rails.root.join('app', 'controllers', 'application_controller.rb')
|
|
296
|
+
application_controller_content = File.read(application_controller_path)
|
|
297
|
+
|
|
298
|
+
# Check if CCCUX is already configured
|
|
299
|
+
if application_controller_content.include?('Cccux::ApplicationControllerConcern') ||
|
|
300
|
+
application_controller_content.include?('include CanCan::ControllerAdditions')
|
|
301
|
+
puts " âšī¸ ApplicationController already includes CCCUX authorization"
|
|
302
|
+
return
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Find the class definition line
|
|
306
|
+
class_line_pattern = /class ApplicationController < ActionController::Base/
|
|
307
|
+
unless application_controller_content.match(class_line_pattern)
|
|
308
|
+
puts " â ī¸ Could not find ApplicationController class definition"
|
|
309
|
+
return
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Add CCCUX concern include
|
|
313
|
+
updated_content = application_controller_content.gsub(
|
|
314
|
+
class_line_pattern,
|
|
315
|
+
"class ApplicationController < ActionController::Base\n include Cccux::ApplicationControllerConcern"
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
File.write(application_controller_path, updated_content)
|
|
319
|
+
puts " â
Added CCCUX authorization to ApplicationController"
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def create_default_roles_and_permissions
|
|
323
|
+
# Create Role Manager role (highest priority)
|
|
324
|
+
role_manager = Cccux::Role.find_or_create_by(name: 'Role Manager') do |role|
|
|
325
|
+
role.description = 'Can manage roles and permissions for all users'
|
|
326
|
+
role.priority = 100
|
|
327
|
+
role.active = true
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Create Basic User role
|
|
331
|
+
basic_user = Cccux::Role.find_or_create_by(name: 'Basic User') do |role|
|
|
332
|
+
role.description = 'Standard user with basic permissions'
|
|
333
|
+
role.priority = 2
|
|
334
|
+
role.active = true
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Create Guest role (lowest priority)
|
|
338
|
+
guest = Cccux::Role.find_or_create_by(name: 'Guest') do |role|
|
|
339
|
+
role.description = 'Limited access user'
|
|
340
|
+
role.priority = 3
|
|
341
|
+
role.active = true
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Create permissions
|
|
345
|
+
permissions = [
|
|
346
|
+
# Role Manager permissions (full access)
|
|
347
|
+
{ action: 'read', subject: 'User' },
|
|
348
|
+
{ action: 'create', subject: 'User' },
|
|
349
|
+
{ action: 'update', subject: 'User' },
|
|
350
|
+
{ action: 'destroy', subject: 'User' },
|
|
351
|
+
{ action: 'read', subject: 'Cccux::Role' },
|
|
352
|
+
{ action: 'create', subject: 'Cccux::Role' },
|
|
353
|
+
{ action: 'update', subject: 'Cccux::Role' },
|
|
354
|
+
{ action: 'destroy', subject: 'Cccux::Role' },
|
|
355
|
+
{ action: 'read', subject: 'Cccux::AbilityPermission' },
|
|
356
|
+
{ action: 'create', subject: 'Cccux::AbilityPermission' },
|
|
357
|
+
{ action: 'update', subject: 'Cccux::AbilityPermission' },
|
|
358
|
+
{ action: 'destroy', subject: 'Cccux::AbilityPermission' },
|
|
359
|
+
|
|
360
|
+
# Basic User permissions (limited access)
|
|
361
|
+
{ action: 'read', subject: 'User' },
|
|
362
|
+
{ action: 'update', subject: 'User' },
|
|
363
|
+
|
|
364
|
+
# Guest permissions (read-only)
|
|
365
|
+
{ action: 'read', subject: 'User' }
|
|
366
|
+
]
|
|
367
|
+
|
|
368
|
+
permissions.each do |perm|
|
|
369
|
+
Cccux::AbilityPermission.find_or_create_by(
|
|
370
|
+
action: perm[:action],
|
|
371
|
+
subject: perm[:subject]
|
|
372
|
+
) do |permission|
|
|
373
|
+
permission.active = true
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Assign permissions to roles
|
|
378
|
+
# Role Manager gets all permissions
|
|
379
|
+
Cccux::AbilityPermission.all.each do |permission|
|
|
380
|
+
Cccux::RoleAbility.find_or_create_by(
|
|
381
|
+
role: role_manager,
|
|
382
|
+
ability_permission: permission
|
|
383
|
+
)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Basic User gets limited permissions
|
|
387
|
+
basic_user_permissions = Cccux::AbilityPermission.where(
|
|
388
|
+
action: ['read', 'update'],
|
|
389
|
+
subject: 'User'
|
|
390
|
+
)
|
|
391
|
+
basic_user_permissions.each do |permission|
|
|
392
|
+
Cccux::RoleAbility.find_or_create_by(
|
|
393
|
+
role: basic_user,
|
|
394
|
+
ability_permission: permission
|
|
395
|
+
)
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# Guest gets read-only permissions
|
|
399
|
+
guest_permissions = Cccux::AbilityPermission.where(
|
|
400
|
+
action: 'read',
|
|
401
|
+
subject: 'User'
|
|
402
|
+
)
|
|
403
|
+
guest_permissions.each do |permission|
|
|
404
|
+
Cccux::RoleAbility.find_or_create_by(
|
|
405
|
+
role: guest,
|
|
406
|
+
ability_permission: permission
|
|
407
|
+
)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
puts " â
Created Role Manager, Basic User, and Guest roles with appropriate permissions"
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def create_default_admin_user
|
|
414
|
+
begin
|
|
415
|
+
if defined?(User) && User.count == 0
|
|
416
|
+
role_manager = Cccux::Role.find_by(name: 'Role Manager')
|
|
417
|
+
|
|
418
|
+
if role_manager
|
|
419
|
+
# Check for ENV vars first
|
|
420
|
+
email = ENV['ADMIN_EMAIL']
|
|
421
|
+
password = ENV['ADMIN_PASSWORD']
|
|
422
|
+
password_confirmation = ENV['ADMIN_PASSWORD_CONFIRMATION'] || password
|
|
423
|
+
|
|
424
|
+
if email && password
|
|
425
|
+
puts " ⥠Creating Role Manager user from environment variables..."
|
|
426
|
+
user = User.create!(email: email, password: password, password_confirmation: password_confirmation)
|
|
427
|
+
Cccux::UserRole.create!(user: user, role: role_manager)
|
|
428
|
+
puts " â
Created Role Manager account: #{email}"
|
|
429
|
+
return
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
puts " đ§ Let's create your first Role Manager account:"
|
|
433
|
+
print " đ§ Enter email address: "
|
|
434
|
+
email = $stdin.gets.chomp
|
|
435
|
+
|
|
436
|
+
while email.blank? || !email.include?('@')
|
|
437
|
+
print " â Please enter a valid email address: "
|
|
438
|
+
email = $stdin.gets.chomp
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
puts " đ Enter password (input will be visible): "
|
|
442
|
+
password = $stdin.gets.chomp
|
|
443
|
+
|
|
444
|
+
if password.blank?
|
|
445
|
+
puts " â ī¸ Password input was blank. Skipping user creation."
|
|
446
|
+
return
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
puts " đ Confirm password (input will be visible): "
|
|
450
|
+
password_confirmation = $stdin.gets.chomp
|
|
451
|
+
|
|
452
|
+
if password_confirmation.blank?
|
|
453
|
+
puts " â ī¸ Password confirmation was blank. Skipping user creation."
|
|
454
|
+
return
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
if password != password_confirmation
|
|
458
|
+
puts " â Passwords don't match. Skipping user creation."
|
|
459
|
+
return
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
user = User.create!(
|
|
463
|
+
email: email,
|
|
464
|
+
password: password,
|
|
465
|
+
password_confirmation: password_confirmation
|
|
466
|
+
)
|
|
467
|
+
Cccux::UserRole.create!(user: user, role: role_manager)
|
|
468
|
+
puts " â
Created Role Manager account: #{email}"
|
|
469
|
+
else
|
|
470
|
+
puts " â ī¸ No Role Manager role found - skipping user creation"
|
|
471
|
+
end
|
|
472
|
+
else
|
|
473
|
+
puts " âšī¸ Users already exist, skipping default Administrator creation"
|
|
474
|
+
end
|
|
475
|
+
rescue => e
|
|
476
|
+
puts " â ī¸ Could not create default admin: #{e.message}"
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def create_home_controller
|
|
481
|
+
# Check if home controller already exists
|
|
482
|
+
home_controller_path = Rails.root.join('app', 'controllers', 'home_controller.rb')
|
|
483
|
+
home_view_path = Rails.root.join('app', 'views', 'home', 'index.html.erb')
|
|
484
|
+
|
|
485
|
+
home_controller_exists = File.exist?(home_controller_path)
|
|
486
|
+
if home_controller_exists
|
|
487
|
+
puts " âšī¸ Home controller already exists"
|
|
488
|
+
else
|
|
489
|
+
# Create home controller
|
|
490
|
+
home_controller_content = <<~RUBY
|
|
491
|
+
class HomeController < ApplicationController
|
|
492
|
+
def index
|
|
493
|
+
# Welcome page for CCCUX powered Rails site
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
RUBY
|
|
497
|
+
File.write(home_controller_path, home_controller_content)
|
|
498
|
+
puts " â
Created home controller at #{home_controller_path}"
|
|
499
|
+
# Create home views directory
|
|
500
|
+
home_views_dir = Rails.root.join('app', 'views', 'home')
|
|
501
|
+
FileUtils.mkdir_p(home_views_dir) unless Dir.exist?(home_views_dir)
|
|
502
|
+
# Create home index view
|
|
503
|
+
home_view_content = <<~ERB
|
|
504
|
+
<div class=\"welcome-section\" style=\"text-align: center; padding: 3rem 0;\">
|
|
505
|
+
<h1 style=\"color: #333; margin-bottom: 1rem; font-size: 2.5rem;\">
|
|
506
|
+
Welcome to your CCCUX powered Rails Site
|
|
507
|
+
</h1>
|
|
508
|
+
<p style=\"color: #666; font-size: 1.2rem; max-width: 600px; margin: 0 auto; line-height: 1.6;\">
|
|
509
|
+
Your Rails application is now equipped with CCCUX, a powerful role-based authorization engine built on CanCanCan. Edit app/views/home/index.html.erb to change this content
|
|
510
|
+
</p>
|
|
511
|
+
<div style=\"margin-top: 2rem;\">
|
|
512
|
+
<% if user_signed_in? %>
|
|
513
|
+
<p style=\"color: #28a745; font-weight: bold;\">
|
|
514
|
+
â
You are signed in as: <%= current_user.email %>
|
|
515
|
+
</p>
|
|
516
|
+
<% if current_user.has_role?('Role Manager') %>
|
|
517
|
+
<p style=\"color: #007bff; margin-top: 1rem;\">
|
|
518
|
+
<a href=\"<%= cccux.root_path %>\" style=\"color: #007bff; text-decoration: none; font-weight: bold;\">
|
|
519
|
+
đ§ Access CCCUX Admin Panel
|
|
520
|
+
</a>
|
|
521
|
+
</p>
|
|
522
|
+
<% end %>
|
|
523
|
+
<% else %>
|
|
524
|
+
<p style=\"color: #6c757d;\">
|
|
525
|
+
<a href=\"<%= new_user_session_path %>\" style=\"color: #007bff; text-decoration: none;\">
|
|
526
|
+
đ Sign in to get started
|
|
527
|
+
</a>
|
|
528
|
+
</p>
|
|
529
|
+
<% end %>
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
ERB
|
|
533
|
+
File.write(home_view_path, home_view_content)
|
|
534
|
+
puts " â
Created home index view at #{home_view_path}"
|
|
535
|
+
end
|
|
536
|
+
# Always check and add root route if needed
|
|
537
|
+
routes_path = Rails.root.join('config', 'routes.rb')
|
|
538
|
+
routes_content = File.read(routes_path)
|
|
539
|
+
unless routes_content.include?("root 'home#index'")
|
|
540
|
+
if routes_content.include?('devise_for :users')
|
|
541
|
+
updated_content = routes_content.gsub(
|
|
542
|
+
/(devise_for :users)/,
|
|
543
|
+
"\\1\n root 'home#index'"
|
|
544
|
+
)
|
|
545
|
+
File.write(routes_path, updated_content)
|
|
546
|
+
puts " â
Added root route to routes.rb"
|
|
547
|
+
else
|
|
548
|
+
puts " â ī¸ Could not find devise_for :users in routes - please manually add: root 'home#index'"
|
|
549
|
+
end
|
|
550
|
+
else
|
|
551
|
+
puts " âšī¸ Root route already exists in routes.rb"
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def create_footer_partial
|
|
556
|
+
# Create the shared directory if it doesn't exist
|
|
557
|
+
shared_dir = Rails.root.join('app', 'views', 'shared')
|
|
558
|
+
FileUtils.mkdir_p(shared_dir) unless Dir.exist?(shared_dir)
|
|
559
|
+
|
|
560
|
+
footer_path = shared_dir.join('_footer.html.erb')
|
|
561
|
+
|
|
562
|
+
# Create footer content
|
|
563
|
+
footer_content = <<~ERB
|
|
564
|
+
<!-- CCCUX Footer - Added by CCCUX setup -->
|
|
565
|
+
<footer class="cccux-footer" style="margin-top: 2rem; padding: 1rem 0; border-top: 1px solid #e5e5e5; background-color: #f8f9fa;">
|
|
566
|
+
<div class="container">
|
|
567
|
+
<div class="row">
|
|
568
|
+
<div class="col-md-6">
|
|
569
|
+
<nav class="footer-nav">
|
|
570
|
+
<a href="<%= main_app.root_path %>" class="footer-link">đ Home</a>
|
|
571
|
+
<% if user_signed_in? && current_user.has_role?('Role Manager') %>
|
|
572
|
+
<span class="footer-separator">|</span>
|
|
573
|
+
<a href="<%= cccux.root_path %>" class="footer-link">âī¸ CCCUX Admin</a>
|
|
574
|
+
<% end %>
|
|
575
|
+
</nav>
|
|
576
|
+
</div>
|
|
577
|
+
<div class="col-md-6 text-end">
|
|
578
|
+
<% if user_signed_in? %>
|
|
579
|
+
<span class="user-info">
|
|
580
|
+
đ¤ <strong><%= current_user.email %></strong>
|
|
581
|
+
<span class="footer-separator">|</span>
|
|
582
|
+
<%= link_to "đĒ Logout", main_app.destroy_user_session_path,
|
|
583
|
+
method: :delete,
|
|
584
|
+
class: "footer-link",
|
|
585
|
+
data: { turbo_method: :delete } %>
|
|
586
|
+
</span>
|
|
587
|
+
<% else %>
|
|
588
|
+
<span class="auth-links">
|
|
589
|
+
<%= link_to "đ Sign In", main_app.new_user_session_path, class: "footer-link" %>
|
|
590
|
+
<span class="footer-separator">|</span>
|
|
591
|
+
<%= link_to "đ Sign Up", main_app.new_user_registration_path, class: "footer-link" %>
|
|
592
|
+
</span>
|
|
593
|
+
<% end %>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
</div>
|
|
597
|
+
</footer>
|
|
598
|
+
|
|
599
|
+
<style>
|
|
600
|
+
.cccux-footer {
|
|
601
|
+
font-size: 0.9rem;
|
|
602
|
+
color: #6c757d;
|
|
603
|
+
}
|
|
604
|
+
.cccux-footer .footer-link {
|
|
605
|
+
color: #007bff;
|
|
606
|
+
text-decoration: none;
|
|
607
|
+
margin: 0 0.5rem;
|
|
608
|
+
}
|
|
609
|
+
.cccux-footer .footer-link:hover {
|
|
610
|
+
color: #0056b3;
|
|
611
|
+
text-decoration: underline;
|
|
612
|
+
}
|
|
613
|
+
.cccux-footer .footer-separator {
|
|
614
|
+
color: #dee2e6;
|
|
615
|
+
margin: 0 0.25rem;
|
|
616
|
+
}
|
|
617
|
+
.cccux-footer .user-info,
|
|
618
|
+
.cccux-footer .auth-links {
|
|
619
|
+
font-size: 0.85rem;
|
|
620
|
+
}
|
|
621
|
+
.cccux-footer .container {
|
|
622
|
+
max-width: 1200px;
|
|
623
|
+
margin: 0 auto;
|
|
624
|
+
padding: 0 1rem;
|
|
625
|
+
}
|
|
626
|
+
.cccux-footer .row {
|
|
627
|
+
display: flex;
|
|
628
|
+
justify-content: space-between;
|
|
629
|
+
align-items: center;
|
|
630
|
+
flex-wrap: wrap;
|
|
631
|
+
}
|
|
632
|
+
.cccux-footer .col-md-6 {
|
|
633
|
+
flex: 1;
|
|
634
|
+
min-width: 300px;
|
|
635
|
+
}
|
|
636
|
+
.cccux-footer .text-end {
|
|
637
|
+
text-align: right;
|
|
638
|
+
}
|
|
639
|
+
@media (max-width: 768px) {
|
|
640
|
+
.cccux-footer .row {
|
|
641
|
+
flex-direction: column;
|
|
642
|
+
gap: 0.5rem;
|
|
643
|
+
}
|
|
644
|
+
.cccux-footer .col-md-6 {
|
|
645
|
+
text-align: center;
|
|
646
|
+
}
|
|
647
|
+
.cccux-footer .text-end {
|
|
648
|
+
text-align: center;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
</style>
|
|
652
|
+
ERB
|
|
653
|
+
|
|
654
|
+
# Write the footer partial
|
|
655
|
+
File.write(footer_path, footer_content)
|
|
656
|
+
puts " â
Created footer partial at #{footer_path}"
|
|
657
|
+
|
|
658
|
+
# Also create a simple include instruction for the application layout
|
|
659
|
+
layout_path = Rails.root.join('app', 'views', 'layouts', 'application.html.erb')
|
|
660
|
+
if File.exist?(layout_path)
|
|
661
|
+
layout_content = File.read(layout_path)
|
|
662
|
+
|
|
663
|
+
# Check if footer is already included
|
|
664
|
+
unless layout_content.include?('render "shared/footer"')
|
|
665
|
+
# Add footer before closing body tag
|
|
666
|
+
if layout_content.include?('</body>')
|
|
667
|
+
updated_content = layout_content.gsub(
|
|
668
|
+
/(\s*)<\/body>/,
|
|
669
|
+
"\\1 <%= render 'shared/footer' %>\n\\1</body>"
|
|
670
|
+
)
|
|
671
|
+
File.write(layout_path, updated_content)
|
|
672
|
+
puts " â
Added footer to application layout"
|
|
673
|
+
else
|
|
674
|
+
puts " â ī¸ Could not find </body> tag in application layout - please manually add: <%= render 'shared/footer' %>"
|
|
675
|
+
end
|
|
676
|
+
else
|
|
677
|
+
puts " âšī¸ Footer already included in application layout"
|
|
678
|
+
end
|
|
679
|
+
else
|
|
680
|
+
puts " â ī¸ Application layout not found - please manually add: <%= render 'shared/footer' %>"
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
def verify_setup
|
|
685
|
+
# Test that User model has CCCUX methods
|
|
686
|
+
user = User.new
|
|
687
|
+
unless user.respond_to?(:has_role?)
|
|
688
|
+
puts "â User model missing CCCUX methods"
|
|
689
|
+
exit 1
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
puts "â
CCCUX methods available on User model"
|
|
693
|
+
|
|
694
|
+
# Test route helpers
|
|
695
|
+
begin
|
|
696
|
+
Rails.application.routes.url_helpers.new_user_session_path
|
|
697
|
+
puts "â
Devise routes working"
|
|
698
|
+
rescue => e
|
|
699
|
+
puts "â Devise routes not working: #{e.message}"
|
|
700
|
+
exit 1
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
end
|