one-for-all-framework 4.3.0 → 4.5.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.
@@ -0,0 +1,143 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Under Construction | One-For-All</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&display=swap" rel="stylesheet">
8
+ <style>
9
+ :root {
10
+ --primary: #6366f1;
11
+ --primary-glow: rgba(99, 102, 241, 0.5);
12
+ --bg: #0f172a;
13
+ --glass: rgba(255, 255, 255, 0.05);
14
+ --glass-border: rgba(255, 255, 255, 0.1);
15
+ }
16
+
17
+ * {
18
+ margin: 0;
19
+ padding: 0;
20
+ box-sizing: border-box;
21
+ font-family: 'Outfit', sans-serif;
22
+ }
23
+
24
+ body {
25
+ background: var(--bg);
26
+ color: white;
27
+ height: 100vh;
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ overflow: hidden;
32
+ background-image:
33
+ radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 40%),
34
+ radial-gradient(circle at 80% 80%, rgba(236, 72, 153, 0.15) 0%, transparent 40%);
35
+ }
36
+
37
+ .container {
38
+ text-align: center;
39
+ padding: 3rem;
40
+ background: var(--glass);
41
+ backdrop-filter: blur(20px);
42
+ border: 1px solid var(--glass-border);
43
+ border-radius: 2rem;
44
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
45
+ max-width: 600px;
46
+ width: 90%;
47
+ animation: fadeIn 1s ease-out;
48
+ }
49
+
50
+ @keyframes fadeIn {
51
+ from { opacity: 0; transform: translateY(20px); }
52
+ to { opacity: 1; transform: translateY(0); }
53
+ }
54
+
55
+ .icon {
56
+ font-size: 5rem;
57
+ margin-bottom: 1.5rem;
58
+ display: inline-block;
59
+ animation: float 3s ease-in-out infinite;
60
+ }
61
+
62
+ @keyframes float {
63
+ 0%, 100% { transform: translateY(0); }
64
+ 50% { transform: translateY(-10px); }
65
+ }
66
+
67
+ h1 {
68
+ font-size: 2.5rem;
69
+ font-weight: 600;
70
+ margin-bottom: 1rem;
71
+ background: linear-gradient(to right, #818cf8, #f472b6);
72
+ -webkit-background-clip: text;
73
+ -webkit-text-fill-color: transparent;
74
+ }
75
+
76
+ p {
77
+ font-size: 1.1rem;
78
+ color: #94a3b8;
79
+ line-height: 1.6;
80
+ margin-bottom: 2rem;
81
+ }
82
+
83
+ .loader {
84
+ width: 100%;
85
+ height: 4px;
86
+ background: rgba(255, 255, 255, 0.1);
87
+ border-radius: 2px;
88
+ overflow: hidden;
89
+ margin-bottom: 2rem;
90
+ }
91
+
92
+ .loader-bar {
93
+ width: 40%;
94
+ height: 100%;
95
+ background: var(--primary);
96
+ box-shadow: 0 0 15px var(--primary-glow);
97
+ border-radius: 2px;
98
+ animation: loading 2s infinite ease-in-out;
99
+ }
100
+
101
+ @keyframes loading {
102
+ 0% { transform: translateX(-100%); }
103
+ 100% { transform: translateX(300%); }
104
+ }
105
+
106
+ .footer {
107
+ font-size: 0.9rem;
108
+ color: #64748b;
109
+ }
110
+
111
+ .admin-link {
112
+ margin-top: 2rem;
113
+ display: block;
114
+ color: var(--primary);
115
+ text-decoration: none;
116
+ font-weight: 500;
117
+ opacity: 0.5;
118
+ transition: opacity 0.3s;
119
+ }
120
+
121
+ .admin-link:hover {
122
+ opacity: 1;
123
+ }
124
+ </style>
125
+ </head>
126
+ <body>
127
+ <div class="container">
128
+ <div class="icon">🚀</div>
129
+ <h1>Under Construction</h1>
130
+ <p>We're working hard to bring you something amazing. Our site is currently undergoing scheduled maintenance. Please check back soon!</p>
131
+
132
+ <div class="loader">
133
+ <div class="loader-bar"></div>
134
+ </div>
135
+
136
+ <div class="footer">
137
+ &copy; <%= Time.now.year %> One-For-All Framework. All rights reserved.
138
+ </div>
139
+
140
+ <a href="/login" class="admin-link">Admin Login</a>
141
+ </div>
142
+ </body>
143
+ </html>
data/bin/ofa CHANGED
@@ -1,5 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # --- Bundler Setup ---
4
+ # This ensures that if we are in a project with a Gemfile, we use the correct
5
+ # gem versions specified in Gemfile.lock, preventing conflicts with system gems.
6
+ if File.exist?(File.join(Dir.pwd, 'Gemfile'))
7
+ begin
8
+ require 'bundler/setup'
9
+ rescue LoadError
10
+ # Bundler not installed, proceed without it
11
+ end
12
+ end
13
+
3
14
  require 'fileutils'
4
15
  require 'optparse'
5
16
  require 'json'
@@ -22,7 +33,7 @@ def help
22
33
  puts " / __ \\/ ____/ / | "
23
34
  puts " / / / / /_ / /| | Framework "
24
35
  puts "/ /_/ / __/ / ___ | Premium MVC "
25
- puts "\\____/_/ /_/ |_| v4.3.0 "
36
+ puts "\\____/_/ /_/ |_| v4.5.0 "
26
37
  puts " "
27
38
  puts "✨ One-For-All Framework CLI ✨"
28
39
  puts "-----------------------------"
@@ -33,6 +44,9 @@ def help
33
44
  puts " ofa g api NAME - Generate a new API controller (JSON)"
34
45
  puts " ofa g model NAME - Generate a new model"
35
46
  puts " ofa g migration NAME - Generate a new migration"
47
+ puts " ofa g mailer NAME ACTION - Generate a new mailer and template"
48
+ puts " ofa g task NAME - Generate a new background task"
49
+ puts " ofa g test NAME - Generate a new unit test"
36
50
  puts " ofa g post TITLE - Create a new post [args: --category, --author, --image]"
37
51
  puts " ofa feature ACTION F - Toggle features: action=enable/disable, F=cms/auth/rich_text"
38
52
  puts " ofa type NAME - Set application type: portfolio, blog, landing_page, e_commerce"
@@ -47,6 +61,9 @@ def help
47
61
  puts " ofa doctor - Check system health (DB, config, gems)"
48
62
  puts " ofa routes - List all registered routes"
49
63
  puts " ofa swagger - Auto-generate OpenAPI/Swagger documentation"
64
+ puts " ofa maintenance ACTION - Toggle maintenance mode (on/off)"
65
+ puts " ofa task NAME - Run a background task"
66
+ puts " ofa test - Run all application tests"
50
67
  puts " ofa run - Start the application server"
51
68
  puts " ofa deploy - Deploy project to production"
52
69
  puts "-----------------------------"
@@ -231,7 +248,7 @@ when 'init'
231
248
  puts " / __ \\/ ____/ / | "
232
249
  puts " / / / / /_ / /| | Framework "
233
250
  puts "/ /_/ / __/ / ___ | Premium MVC "
234
- puts "\\____/_/ /_/ |_| v4.3.0 "
251
+ puts "\\____/_/ /_/ |_| v4.5.0 "
235
252
  puts " "
236
253
  puts "Initializing One-For-All project as '#{app_type}' in #{PROJECT_ROOT}..."
237
254
 
@@ -262,7 +279,7 @@ when 'init'
262
279
  puts "-----------------------------\n"
263
280
 
264
281
  # Create directories
265
- dirs = ['app/controllers', 'app/models', 'app/views', 'config', 'db/migrations', 'public/css', 'public/js', 'public/images', 'public/images/uploads']
282
+ dirs = ['app/controllers', 'app/models', 'app/views', 'app/mailers', 'lib/tasks', 'test', 'config', 'db/migrations', 'public/css', 'public/js', 'public/images', 'public/images/uploads']
266
283
  dirs.each { |dir| FileUtils.mkdir_p(File.join(PROJECT_ROOT, dir)) }
267
284
 
268
285
  # Copy framework core migrations
@@ -274,6 +291,21 @@ when 'init'
274
291
  end
275
292
  end
276
293
 
294
+ # Copy framework core helpers and test assets
295
+ ['lib/task_helper.rb', 'app/mailers/application_mailer.rb', 'test/test_helper.rb'].each do |file|
296
+ src = File.join(FRAMEWORK_ROOT, file)
297
+ dest = File.join(PROJECT_ROOT, file)
298
+ FileUtils.mkdir_p(File.dirname(dest))
299
+ if File.exist?(src)
300
+ content = File.read(src)
301
+ # Inject FRAMEWORK_ROOT into test_helper.rb
302
+ if file == 'test/test_helper.rb'
303
+ content.gsub!("require_relative '../config/boot'", "$LOAD_PATH.unshift '#{FRAMEWORK_ROOT}'\nrequire 'config/boot'")
304
+ end
305
+ File.write(dest, content)
306
+ end
307
+ end
308
+
277
309
  # Create .env
278
310
  env_content = []
279
311
  env_content << "EKS_ENV=development"
@@ -296,12 +328,16 @@ when 'init'
296
328
  # Middleware setup
297
329
  use EksCent::Middleware::ShowExceptions
298
330
  use EksCent::Middleware::Session, secret: EksCent.secret_key_base
331
+ use MaintenanceMiddleware
299
332
  use AuthMiddleware
300
333
  use JwtMiddleware
301
334
  use CSRFMiddleware
302
335
  use EksCent::Middleware::Static, root: 'public'
303
336
  use EksCent::Middleware::Logger
304
337
 
338
+ # Apply plugin routes
339
+ OFA.apply_pending_routes(ROUTES) if defined?(OFA)
340
+
305
341
  run ROUTES
306
342
  RUBY
307
343
  File.write(File.join(PROJECT_ROOT, 'config.ru'), config_ru_content)
@@ -321,6 +357,8 @@ when 'init'
321
357
  gem 'mysql2'
322
358
  gem 'kramdown'
323
359
  gem 'kramdown-parser-gfm'
360
+ gem 'mail'
361
+ gem 'minitest'
324
362
  RUBY
325
363
  File.write(File.join(PROJECT_ROOT, 'Gemfile'), gemfile_content)
326
364
 
@@ -499,6 +537,58 @@ when 'g'
499
537
  File.write(file_name, content)
500
538
  puts "Created API Controller: #{file_name}"
501
539
  puts "💡 Don't forget to register it in config/routes.rb"
540
+ elsif sub == 'mailer' && name
541
+ action = ARGV.shift || 'welcome'
542
+ class_name = name.capitalize + "Mailer"
543
+ file_name = File.join(PROJECT_ROOT, "app/mailers/#{name.downcase}_mailer.rb")
544
+ content = <<~RUBY
545
+ class #{class_name} < ApplicationMailer
546
+ def #{action}(user)
547
+ mail(
548
+ to: user.email,
549
+ subject: "Welcome to our platform!",
550
+ template: "#{name.downcase}_mailer/#{action}",
551
+ locals: { user: user }
552
+ )
553
+ end
554
+ end
555
+ RUBY
556
+ File.write(file_name, content)
557
+
558
+ # Create template
559
+ template_dir = File.join(PROJECT_ROOT, "app/views/mailers/#{name.downcase}_mailer")
560
+ FileUtils.mkdir_p(template_dir)
561
+ template_file = File.join(template_dir, "#{action}.erb")
562
+ File.write(template_file, "<h1>Hello <%= @user.username %></h1>\n<p>Welcome to One-For-All Framework!</p>")
563
+
564
+ puts "Created Mailer: #{file_name}"
565
+ puts "Created Template: #{template_file}"
566
+ elsif sub == 'task' && name
567
+ dir_path = File.join(PROJECT_ROOT, "lib/tasks")
568
+ FileUtils.mkdir_p(dir_path)
569
+ file_name = File.join(dir_path, "#{name.downcase}.rb")
570
+ content = <<~RUBY
571
+ desc "Description for #{name} task"
572
+ task :#{name.downcase} do
573
+ puts "Running task: #{name}"
574
+ # Your background job logic here
575
+ end
576
+ RUBY
577
+ File.write(file_name, content)
578
+ puts "Created Task: #{file_name}"
579
+ elsif sub == 'test' && name
580
+ file_name = File.join(PROJECT_ROOT, "test/#{name.downcase}_test.rb")
581
+ content = <<~RUBY
582
+ require_relative 'test_helper'
583
+
584
+ class #{name.capitalize}Test < Minitest::Test
585
+ def test_example
586
+ assert true
587
+ end
588
+ end
589
+ RUBY
590
+ File.write(file_name, content)
591
+ puts "Created Test: #{file_name}"
502
592
  elsif sub == 'model' && name
503
593
  class_name = name.capitalize
504
594
  file_name = File.join(PROJECT_ROOT, "app/models/#{name.downcase}.rb")
@@ -534,8 +624,28 @@ when 'g'
534
624
  content = "<h1>#{name}</h1>\n<p>Author: #{options[:author] || 'Admin'}</p>\n<p>Category: #{options[:category] || 'General'}</p>"
535
625
  File.write(file_name, content)
536
626
  puts "Created post: #{file_name}"
627
+ elsif sub == 'plugin' && name
628
+ dir_path = File.join(PROJECT_ROOT, "plugins/#{name.downcase}")
629
+ FileUtils.mkdir_p(dir_path)
630
+ file_name = File.join(dir_path, "init.rb")
631
+ content = <<~RUBY
632
+ # Plugin: #{name.capitalize}
633
+ # Created at: #{Time.now}
634
+
635
+ OFA.on_boot do
636
+ puts "🚀 Plugin #{name.capitalize} loaded!"
637
+ end
638
+
639
+ # Example route added by plugin
640
+ # OFA.add_route(:get, '/#{name.downcase}') do |req, res|
641
+ # res.body << "Hello from #{name.capitalize} Plugin!"
642
+ # end
643
+ RUBY
644
+ File.write(file_name, content)
645
+ puts "Created Plugin: #{dir_path}"
646
+ puts "💡 Edit #{file_name} to start building your plugin."
537
647
  else
538
- puts "Usage: ofa g [controller|model|migration|post] NAME"
648
+ puts "Usage: ofa g [controller|api|model|migration|mailer|task|test|post|plugin] NAME"
539
649
  end
540
650
 
541
651
  when 'feature'
@@ -545,7 +655,8 @@ when 'feature'
545
655
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
546
656
  config = JSON.parse(File.read(config_path))
547
657
  config[feature] = (action == 'enable')
548
- File.write(config_path, JSON.pretty_generate(config))
658
+ File.open("#{config_path}.tmp", 'w') { |f| f.write(JSON.pretty_generate(config)) }
659
+ File.rename("#{config_path}.tmp", config_path)
549
660
  puts "Feature '#{feature}' has been #{action}d."
550
661
 
551
662
  if action == 'enable' && feature == 'cms' && !config['auth']
@@ -564,7 +675,8 @@ when 'type'
564
675
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
565
676
  config = JSON.parse(File.read(config_path))
566
677
  config['type'] = name
567
- File.write(config_path, JSON.pretty_generate(config))
678
+ File.open("#{config_path}.tmp", 'w') { |f| f.write(JSON.pretty_generate(config)) }
679
+ File.rename("#{config_path}.tmp", config_path)
568
680
  puts "Application type set to '#{name}'."
569
681
 
570
682
  when 'theme'
@@ -577,7 +689,8 @@ when 'theme'
577
689
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
578
690
  config = JSON.parse(File.read(config_path))
579
691
  config['theme'] = name
580
- File.write(config_path, JSON.pretty_generate(config))
692
+ File.open("#{config_path}.tmp", 'w') { |f| f.write(JSON.pretty_generate(config)) }
693
+ File.rename("#{config_path}.tmp", config_path)
581
694
  puts "Application theme set to '#{name}'."
582
695
 
583
696
  when 'storage'
@@ -593,6 +706,19 @@ when 'storage'
593
706
  File.write(config_path, JSON.pretty_generate(config))
594
707
  puts "Application storage set to '#{name}'."
595
708
 
709
+ when 'maintenance'
710
+ ensure_initialized!
711
+ action = ARGV.shift
712
+ unless %w[on off].include?(action)
713
+ puts "Usage: ofa maintenance [on|off]"
714
+ exit 1
715
+ end
716
+ config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
717
+ config = JSON.parse(File.read(config_path))
718
+ config['maintenance'] = (action == 'on')
719
+ File.write(config_path, JSON.pretty_generate(config))
720
+ puts "Maintenance mode has been turned #{action}."
721
+
596
722
  when 'reset-password'
597
723
  ENV['SKIP_MODELS'] = '1'
598
724
  Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
@@ -640,7 +766,8 @@ when 'db'
640
766
  env_lines = File.exist?(env_path) ? File.readlines(env_path) : []
641
767
  env_lines.reject! { |l| l.start_with?('DATABASE_URL=') }
642
768
  env_lines << "DATABASE_URL=#{db_name}\n"
643
- File.write(env_path, env_lines.join)
769
+ File.open("#{env_path}.tmp", 'w') { |f| f.write(env_lines.join) }
770
+ File.rename("#{env_path}.tmp", env_path)
644
771
  puts "✅ Connection string saved to .env"
645
772
  end
646
773
  when 'sqlite'
@@ -648,7 +775,8 @@ when 'db'
648
775
  else
649
776
  config = { "adapter" => type, "host" => "localhost", "user" => "root", "password" => "", "database" => db_name || "one_for_all" }
650
777
  end
651
- File.write(config_path, JSON.pretty_generate(config))
778
+ File.open("#{config_path}.tmp", 'w') { |f| f.write(JSON.pretty_generate(config)) }
779
+ File.rename("#{config_path}.tmp", config_path)
652
780
  puts "Switched to #{type} mode."
653
781
  when 'migrate'
654
782
  run_migrations
@@ -733,7 +861,7 @@ when 'console'
733
861
  puts " / __ \\/ ____/ / | "
734
862
  puts " / / / / /_ / /| | Framework "
735
863
  puts "/ /_/ / __/ / ___ | Console (REPL) "
736
- puts "\\____/_/ /_/ |_| v4.3.0 "
864
+ puts "\\____/_/ /_/ |_| v4.5.0 "
737
865
  puts " "
738
866
  puts "✨ Loading environment... (Type 'exit' to quit)"
739
867
 
@@ -845,6 +973,63 @@ when 'deploy'
845
973
  puts " This framework supports deployment via Docker or Git Push."
846
974
  end
847
975
 
976
+ when 'task'
977
+ ensure_initialized!
978
+ name = ARGV.shift
979
+ if name.nil?
980
+ puts "Usage: ofa task NAME"
981
+ # List available tasks
982
+ tasks_dir = File.join(PROJECT_ROOT, 'lib/tasks')
983
+ if Dir.exist?(tasks_dir)
984
+ puts "\nAvailable tasks:"
985
+ Dir.glob(File.join(tasks_dir, '*.rb')).each do |f|
986
+ puts " - #{File.basename(f, '.rb')}"
987
+ end
988
+ end
989
+ exit 1
990
+ end
991
+
992
+ # Load framework & app
993
+ Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
994
+ require File.join(FRAMEWORK_ROOT, 'config', 'boot')
995
+ require File.join(FRAMEWORK_ROOT, 'lib', 'task_helper')
996
+
997
+ # Load all tasks in lib/tasks
998
+ Dir.glob(File.join(PROJECT_ROOT, 'lib/tasks/*.rb')).each { |f| require f }
999
+
1000
+ run_task(name)
1001
+
1002
+ when 'test'
1003
+ ensure_initialized!
1004
+ puts "🧪 Running tests..."
1005
+ puts "------------------------------------------"
1006
+
1007
+ # Set environment to test
1008
+ ENV['EKS_ENV'] = 'test'
1009
+ Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
1010
+
1011
+ # Add project root to load path
1012
+ $LOAD_PATH.unshift PROJECT_ROOT
1013
+ $LOAD_PATH.unshift File.join(PROJECT_ROOT, 'test')
1014
+
1015
+ # Find all tests (support both _test.rb and _spec.rb)
1016
+ if ARGV.empty?
1017
+ test_files = Dir.glob(File.join(PROJECT_ROOT, 'test/**/{*_test.rb,*_spec.rb}'))
1018
+ else
1019
+ test_files = ARGV.map { |arg| File.expand_path(arg, PROJECT_ROOT) }
1020
+ end
1021
+
1022
+ if test_files.empty?
1023
+ puts "❌ No tests found in test/ directory."
1024
+ exit 1
1025
+ end
1026
+
1027
+ # Run them by requiring
1028
+ test_files.each { |f| require f }
1029
+
1030
+ # Trigger EksaMination execution if available
1031
+ EksaMination.run if defined?(EksaMination)
1032
+
848
1033
  else
849
1034
  help
850
1035
  end
data/config/boot.rb CHANGED
@@ -9,6 +9,8 @@ begin
9
9
  rescue LoadError
10
10
  end
11
11
 
12
+ require_relative '../lib/plugin_helper'
13
+
12
14
  # Basic project structure constants
13
15
  APP_ROOT ||= File.expand_path('..', __dir__)
14
16
 
@@ -93,7 +95,7 @@ require_relative 'database'
93
95
 
94
96
  # Autoloading (Framework Core first, then APP_ROOT)
95
97
  framework_app = File.expand_path('../app', __dir__)
96
- ['controllers', 'models', 'middleware', 'helpers'].each do |folder|
98
+ ['controllers', 'models', 'middleware', 'helpers', 'mailers'].each do |folder|
97
99
  next if folder == 'models' && ENV['SKIP_MODELS']
98
100
  loaded = []
99
101
  # Load framework core
@@ -110,6 +112,14 @@ framework_app = File.expand_path('../app', __dir__)
110
112
  end
111
113
  end
112
114
 
115
+ # Load Plugins
116
+ plugins_dir = File.join(APP_ROOT, 'plugins')
117
+ if File.directory?(plugins_dir)
118
+ Dir.glob(File.join(plugins_dir, '**', '*.rb')).each do |plugin_file|
119
+ require plugin_file
120
+ end
121
+ end
122
+
113
123
  # ─── Routes DSL Extensions ─────────────────────────────────────────────────────
114
124
  # Extends EksCent::Router with a `resources` helper that auto-generates RESTful
115
125
  # routes (index, show, new, create, edit, update, destroy) for a given resource.
@@ -151,3 +161,6 @@ end
151
161
 
152
162
  # Load routes
153
163
  require_relative 'routes'
164
+
165
+ # Run Plugin Boot Hooks
166
+ OFA.run_boot_hooks if defined?(OFA)
data/config/database.rb CHANGED
@@ -130,6 +130,18 @@ if DB
130
130
  end
131
131
  end
132
132
 
133
+ unless DB.table_exists?(:activity_logs)
134
+ DB.create_table :activity_logs do
135
+ primary_key :id
136
+ String :user_id
137
+ String :action, null: false
138
+ String :target_type
139
+ String :target_id
140
+ Text :details
141
+ DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
142
+ end
143
+ end
144
+
133
145
  # Quick Migration for existing tables
134
146
  if DB.table_exists?(:pages)
135
147
  DB.alter_table(:pages) { add_column :is_active, TrueClass, default: true unless DB[:pages].columns.include?(:is_active) }
data/config/features.json CHANGED
@@ -4,5 +4,6 @@
4
4
  "type": "landing_page",
5
5
  "theme": "light_sidebar",
6
6
  "storage": "cloudinary",
7
- "rich_text": true
7
+ "rich_text": true,
8
+ "maintenance": false
8
9
  }
data/config/routes.rb CHANGED
@@ -61,6 +61,10 @@ ROUTES = EksCent::Router.new do
61
61
  DashboardController.new(req, res).upload
62
62
  end
63
63
 
64
+ get '/dashboard/logs' do |req, res|
65
+ ActivityLogsController.new(req, res).index
66
+ end
67
+
64
68
  # Resourceful CMS Routes
65
69
  resources :pages, prefix: '/dashboard'
66
70
  resources :posts, prefix: '/dashboard'
data/config.ru CHANGED
@@ -3,9 +3,13 @@ require_relative 'config/boot'
3
3
  # Middleware setup
4
4
  use EksCent::Middleware::ShowExceptions
5
5
  use EksCent::Middleware::Session, secret: EksCent.secret_key_base
6
+ use MaintenanceMiddleware
6
7
  use AuthMiddleware
7
8
  use CSRFMiddleware
8
9
  use EksCent::Middleware::Static, root: 'public'
9
10
  use EksCent::Middleware::Logger
10
11
 
12
+ # Apply plugin routes
13
+ OFA.apply_pending_routes(ROUTES) if defined?(OFA)
14
+
11
15
  run ROUTES
data/db/data.sqlite3 CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  Sequel.migration do
2
2
  change do
3
- create_table(:products) do
3
+ create_table?(:products) do
4
4
  primary_key :id
5
5
  String :name, null: false
6
6
  String :slug, null: false, unique: true
@@ -0,0 +1,13 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table(:activity_logs) do
4
+ primary_key :id
5
+ String :user_id
6
+ String :action, null: false
7
+ String :target_type
8
+ String :target_id
9
+ Text :details
10
+ DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:activity_logs) do
4
+ set_column_type :user_id, String
5
+ end
6
+ end
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: one-for-all-framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ishikawa Uta
@@ -200,6 +200,7 @@ files:
200
200
  - LICENSE
201
201
  - Procfile
202
202
  - README.md
203
+ - app/controllers/activity_logs_controller.rb
203
204
  - app/controllers/api_controller.rb
204
205
  - app/controllers/application_controller.rb
205
206
  - app/controllers/auth_controller.rb
@@ -210,9 +211,12 @@ files:
210
211
  - app/controllers/products_controller.rb
211
212
  - app/controllers/projects_controller.rb
212
213
  - app/helpers/cloudinary_helper.rb
214
+ - app/mailers/application_mailer.rb
213
215
  - app/middleware/auth_middleware.rb
214
216
  - app/middleware/csrf_middleware.rb
215
217
  - app/middleware/jwt_middleware.rb
218
+ - app/middleware/maintenance_middleware.rb
219
+ - app/models/activity_log.rb
216
220
  - app/models/page.rb
217
221
  - app/models/post.rb
218
222
  - app/models/product.rb
@@ -220,6 +224,7 @@ files:
220
224
  - app/models/user.rb
221
225
  - app/views/blog_home.erb
222
226
  - app/views/cart_index.erb
227
+ - app/views/cms/activity_logs.erb
223
228
  - app/views/cms/pages_form.erb
224
229
  - app/views/cms/pages_index.erb
225
230
  - app/views/cms/posts_form.erb
@@ -234,6 +239,7 @@ files:
234
239
  - app/views/index.erb
235
240
  - app/views/layout.erb
236
241
  - app/views/login.erb
242
+ - app/views/maintenance.erb
237
243
  - app/views/page.erb
238
244
  - app/views/portfolio.erb
239
245
  - app/views/post.erb
@@ -254,7 +260,8 @@ files:
254
260
  - db/data.sqlite3
255
261
  - db/development.sqlite3
256
262
  - db/migrations/20260502000000_create_products.rb
257
- - db/target.sqlite3
263
+ - db/migrations/20260507000000_create_activity_logs.rb
264
+ - db/migrations/20260507000001_fix_activity_logs_user_id.rb
258
265
  - ofa
259
266
  - public/css/cms.css
260
267
  - public/images/logo.jpg
data/db/target.sqlite3 DELETED
Binary file