one-for-all-framework 2.0.0 → 4.0.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.
data/bin/ofa CHANGED
@@ -22,7 +22,7 @@ def help
22
22
  puts " / __ \\/ ____/ / | "
23
23
  puts " / / / / /_ / /| | Framework "
24
24
  puts "/ /_/ / __/ / ___ | Premium MVC "
25
- puts "\\____/_/ /_/ |_| v2.0.0 "
25
+ puts "\\____/_/ /_/ |_| v4.0.0 "
26
26
  puts " "
27
27
  puts "✨ One-For-All Framework CLI ✨"
28
28
  puts "-----------------------------"
@@ -34,11 +34,12 @@ def help
34
34
  puts " ofa g migration NAME - Generate a new migration"
35
35
  puts " ofa g post TITLE - Create a new post [args: --category, --author, --image]"
36
36
  puts " ofa feature ACTION F - Toggle features: action=enable/disable, F=cms/auth"
37
- puts " ofa type NAME - Set application type: portfolio, blog, landing_page"
37
+ puts " ofa type NAME - Set application type: portfolio, blog, landing_page, e_commerce"
38
38
  puts " ofa theme NAME - Set UI theme: light_glass, dark_glass, cyber_sidebar, retro_terminal, light_sidebar"
39
39
  puts " ofa storage NAME - Set image storage: local, cloudinary"
40
40
  puts " ofa reset-password USR PWD - Reset admin account password"
41
41
  puts " ofa db switch TYPE [NAME] - Switch DB: sqlite, mysql, mariadb, mongodb, postgres"
42
+ puts " ofa db migrate-data TYPE [NAME] - Migrate data to another DB"
42
43
  puts " ofa db migrate - Run database migrations"
43
44
  puts " ofa migrate - Run database migrations (alias for db migrate)"
44
45
  puts " ofa run - Start the application server"
@@ -49,6 +50,7 @@ end
49
50
 
50
51
  def run_migrations
51
52
  Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
53
+ ENV['SKIP_MODELS'] = '1'
52
54
  require File.join(FRAMEWORK_ROOT, 'config', 'boot')
53
55
  puts "Running migrations..."
54
56
  migration_path = File.join(PROJECT_ROOT, "db/migrations")
@@ -66,6 +68,117 @@ def run_migrations
66
68
  end
67
69
  end
68
70
 
71
+ def perform_db_migration(target_type, target_name)
72
+ # 1. Initialize source environment
73
+ Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
74
+ require File.join(FRAMEWORK_ROOT, 'config', 'boot')
75
+ source_db = DB
76
+
77
+ puts "📦 Starting data migration: #{DB_CONFIG['adapter']} -> #{target_type}..."
78
+
79
+ # 2. Setup target connection
80
+ target_db = nil
81
+ target_mongo = nil
82
+
83
+ if ['mongodb', 'mongo'].include?(target_type)
84
+ require 'mongo'
85
+ target_mongo = Mongo::Client.new(target_name)
86
+ target_db = Sequel.connect("sqlite://db/data.sqlite3")
87
+ elsif target_type == 'sqlite'
88
+ target_db = Sequel.connect("sqlite://#{target_name || 'db/production.sqlite3'}")
89
+ else
90
+ target_db = Sequel.connect("#{target_type}://root:@localhost/#{target_name}")
91
+ end
92
+
93
+ # 3. Ensure target tables exist
94
+ if target_db
95
+ target_db.extension :pagination
96
+ # Re-use the schema creation logic by mimicking a mini-boot
97
+ # For simplicity, we'll just create core tables if they don't exist
98
+ [:users, :pages, :posts, :projects, :products].each do |table|
99
+ unless target_db.table_exists?(table)
100
+ # Copy schema from source (very basic approach)
101
+ schema = source_db.schema(table)
102
+ target_db.create_table(table) do
103
+ schema.each do |col_name, col_info|
104
+ column col_name, col_info[:db_type], primary_key: col_info[:primary_key], allow_null: col_info[:allow_null]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # 4. Migrate data
112
+ [:users, :pages, :posts, :projects, :products].each do |table|
113
+ print " Migrating #{table}... "
114
+ rows = []
115
+
116
+ # Try fetching from Mongo if it exists
117
+ source_mongo = defined?(MONGO_CLIENT) ? MONGO_CLIENT : nil
118
+ if source_mongo
119
+ begin
120
+ mongo_rows = source_mongo[table].find.to_a
121
+ if mongo_rows.any?
122
+ rows = mongo_rows.map do |r|
123
+ r[:id] = r[:_id].to_s if r[:_id]
124
+ r.delete(:_id)
125
+ r
126
+ end
127
+ end
128
+ rescue
129
+ # Collection might not exist in Mongo, fallback to SQL
130
+ end
131
+ end
132
+
133
+ # Fallback to SQL if no rows found in Mongo
134
+ if rows.empty?
135
+ begin
136
+ rows = source_db[table].all
137
+ rescue
138
+ rows = []
139
+ end
140
+ end
141
+
142
+ # Clear target table before migrating to avoid duplicates
143
+ if target_db && target_db.table_exists?(table)
144
+ target_db[table].delete
145
+ end
146
+
147
+ count = 0
148
+ rows.each do |row|
149
+ if target_type == 'mongodb' && table == :users
150
+ # Users go to Mongo in Mongo mode
151
+ target_mongo[:users].update_one({ username: row[:username] }, { "$set" => row.reject{|k| k == :id} }, { upsert: true })
152
+ elsif target_db
153
+ # Deep cleaning and type conversion for SQLite compatibility
154
+ target_columns = target_db[table].columns
155
+ clean_row = {}
156
+ row.each do |k, v|
157
+ sym_k = k.to_sym
158
+ if target_columns.include?(sym_k) && sym_k != :id
159
+ if v.is_a?(BSON::ObjectId)
160
+ clean_row[sym_k] = v.to_s
161
+ elsif v.is_a?(Time)
162
+ clean_row[sym_k] = v.strftime('%Y-%m-%d %H:%M:%S')
163
+ else
164
+ clean_row[sym_k] = v
165
+ end
166
+ end
167
+ end
168
+ target_db[table].insert(clean_row)
169
+ end
170
+ count += 1
171
+ end
172
+ puts "#{count} rows."
173
+ end
174
+
175
+ # 5. Update configuration to point to new DB
176
+ absolute_ofa_path = File.expand_path(__FILE__)
177
+ system("ruby #{absolute_ofa_path} db switch #{target_type} #{target_name}")
178
+
179
+ puts "✅ Migration successful!"
180
+ end
181
+
69
182
  def ensure_initialized!
70
183
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
71
184
  unless File.exist?(config_path)
@@ -113,7 +226,7 @@ when 'init'
113
226
  puts " / __ \\/ ____/ / | "
114
227
  puts " / / / / /_ / /| | Framework "
115
228
  puts "/ /_/ / __/ / ___ | Premium MVC "
116
- puts "\\____/_/ /_/ |_| v2.0.0 "
229
+ puts "\\____/_/ /_/ |_| v4.0.0 "
117
230
  puts " "
118
231
  puts "Initializing One-For-All project as '#{app_type}' in #{PROJECT_ROOT}..."
119
232
 
@@ -322,6 +435,14 @@ when 'init'
322
435
  def index; end
323
436
  end
324
437
  RUBY
438
+ when 'e_commerce'
439
+ puts " Scaffolding E-Commerce starter..."
440
+ File.write(File.join(PROJECT_ROOT, 'app/controllers/products_controller.rb'), <<~RUBY)
441
+ require_relative 'application_controller'
442
+ class ProductsController < ApplicationController
443
+ def index; end
444
+ end
445
+ RUBY
325
446
  end
326
447
 
327
448
  puts "Done! Run 'ofa run' to start your app."
@@ -396,8 +517,8 @@ when 'feature'
396
517
  when 'type'
397
518
  ensure_initialized!
398
519
  name = ARGV.shift
399
- unless %w[landing_page portfolio blog].include?(name)
400
- puts "❌ Error: Invalid app type '#{name}'. Choose: landing_page, portfolio, blog."
520
+ unless %w[landing_page portfolio blog e_commerce].include?(name)
521
+ puts "❌ Error: Invalid app type '#{name}'. Choose: landing_page, portfolio, blog, e_commerce."
401
522
  exit 1
402
523
  end
403
524
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
@@ -433,8 +554,10 @@ when 'storage'
433
554
  puts "Application storage set to '#{name}'."
434
555
 
435
556
  when 'reset-password'
557
+ ENV['SKIP_MODELS'] = '1'
436
558
  Object.const_set(:APP_ROOT, PROJECT_ROOT) unless defined?(APP_ROOT)
437
559
  require File.join(FRAMEWORK_ROOT, 'config', 'boot')
560
+ require File.join(FRAMEWORK_ROOT, 'app', 'models', 'user.rb')
438
561
  user_name = ARGV.shift
439
562
  new_pwd = ARGV.shift
440
563
  if user_name.nil? || new_pwd.nil?
@@ -470,8 +593,16 @@ when 'db'
470
593
  type = ARGV.shift
471
594
  db_name = ARGV.shift
472
595
  case type
473
- when 'env'
596
+ when 'env', 'mongo', 'mongodb'
474
597
  config = { "adapter" => "env" }
598
+ if db_name && db_name.start_with?('mongodb')
599
+ env_path = File.join(PROJECT_ROOT, '.env')
600
+ env_lines = File.exist?(env_path) ? File.readlines(env_path) : []
601
+ env_lines.reject! { |l| l.start_with?('DATABASE_URL=') }
602
+ env_lines << "DATABASE_URL=#{db_name}\n"
603
+ File.write(env_path, env_lines.join)
604
+ puts "✅ Connection string saved to .env"
605
+ end
475
606
  when 'sqlite'
476
607
  config = { "adapter" => "sqlite", "database" => db_name || "db/development.sqlite3" }
477
608
  else
@@ -481,6 +612,14 @@ when 'db'
481
612
  puts "Switched to #{type} mode."
482
613
  when 'migrate'
483
614
  run_migrations
615
+ when 'migrate-data'
616
+ target_type = ARGV.shift
617
+ target_name = ARGV.shift
618
+ if target_type.nil?
619
+ puts "Usage: ofa db migrate-data TYPE [NAME/URL]"
620
+ exit 1
621
+ end
622
+ perform_db_migration(target_type, target_name)
484
623
  end
485
624
 
486
625
  when 'run'
data/config/boot.rb CHANGED
@@ -76,6 +76,7 @@ require_relative 'database'
76
76
  # Autoloading (Framework Core first, then APP_ROOT)
77
77
  framework_app = File.expand_path('../app', __dir__)
78
78
  ['controllers', 'models', 'middleware', 'helpers'].each do |folder|
79
+ next if folder == 'models' && ENV['SKIP_MODELS']
79
80
  loaded = []
80
81
  # Load framework core
81
82
  Dir.glob(File.join(framework_app, folder, '*.rb')).each do |f|
data/config/database.json CHANGED
@@ -1,4 +1,3 @@
1
1
  {
2
- "adapter": "sqlite",
3
- "database": "db/development.sqlite3"
2
+ "adapter": "env"
4
3
  }
data/config/database.rb CHANGED
@@ -114,6 +114,22 @@ if DB
114
114
  end
115
115
  end
116
116
 
117
+ unless DB.table_exists?(:products)
118
+ DB.create_table :products do
119
+ primary_key :id
120
+ String :name, null: false
121
+ String :slug, null: false, unique: true
122
+ String :description, text: true
123
+ Float :price, default: 0.0
124
+ Integer :stock, default: 0
125
+ String :image_url
126
+ String :category
127
+ TrueClass :is_active, default: true
128
+ DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
129
+ DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
130
+ end
131
+ end
132
+
117
133
  # Quick Migration for existing tables
118
134
  if DB.table_exists?(:pages)
119
135
  DB.alter_table(:pages) { add_column :is_active, TrueClass, default: true unless DB[:pages].columns.include?(:is_active) }
data/config/routes.rb CHANGED
@@ -11,11 +11,42 @@ ROUTES = EksCent::Router.new do
11
11
  when 'blog'
12
12
  posts = Post.where(is_active: true).order(Sequel.desc(:created_at)).all
13
13
  res.render 'blog_home', title: "Blog - One-For-All", posts: posts
14
+ when 'e_commerce'
15
+ ProductsController.new(req, res).index
14
16
  else
15
17
  res.render 'index', title: "One-For-All Framework"
16
18
  end
17
19
  end
18
20
 
21
+ # --- E-Commerce Routes ---
22
+ get '/products' do |req, res|
23
+ ProductsController.new(req, res).index
24
+ end
25
+
26
+ get '/products/:slug' do |req, res|
27
+ ProductsController.new(req, res).show
28
+ end
29
+
30
+ get '/cart' do |req, res|
31
+ CartController.new(req, res).index
32
+ end
33
+
34
+ post '/cart/add' do |req, res|
35
+ CartController.new(req, res).add
36
+ end
37
+
38
+ post '/cart/update' do |req, res|
39
+ CartController.new(req, res).update
40
+ end
41
+
42
+ post '/cart/remove' do |req, res|
43
+ CartController.new(req, res).remove
44
+ end
45
+
46
+ post '/cart/clear' do |req, res|
47
+ CartController.new(req, res).clear
48
+ end
49
+
19
50
  get '/docs' do |req, res|
20
51
  res.render 'docs', title: "Documentation - One-For-All"
21
52
  end
@@ -33,6 +64,7 @@ ROUTES = EksCent::Router.new do
33
64
  resources :pages, prefix: '/dashboard'
34
65
  resources :posts, prefix: '/dashboard'
35
66
  resources :projects, prefix: '/dashboard'
67
+ resources :products, prefix: '/dashboard'
36
68
 
37
69
  # Auth Routes
38
70
  get '/login' do |req, res|
data/db/data.sqlite3 CHANGED
Binary file
Binary file
@@ -0,0 +1,17 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table(:products) do
4
+ primary_key :id
5
+ String :name, null: false
6
+ String :slug, null: false, unique: true
7
+ String :description, text: true
8
+ Float :price, default: 0.0
9
+ Integer :stock, default: 0
10
+ String :image_url
11
+ String :category
12
+ TrueClass :is_active, default: true
13
+ DateTime :created_at
14
+ DateTime :updated_at
15
+ end
16
+ end
17
+ end
data/db/target.sqlite3 ADDED
Binary file
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: 2.0.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ishikawa Uta
@@ -188,22 +188,28 @@ files:
188
188
  - app/controllers/api_controller.rb
189
189
  - app/controllers/application_controller.rb
190
190
  - app/controllers/auth_controller.rb
191
+ - app/controllers/cart_controller.rb
191
192
  - app/controllers/dashboard_controller.rb
192
193
  - app/controllers/pages_controller.rb
193
194
  - app/controllers/posts_controller.rb
195
+ - app/controllers/products_controller.rb
194
196
  - app/controllers/projects_controller.rb
195
197
  - app/helpers/cloudinary_helper.rb
196
198
  - app/middleware/auth_middleware.rb
197
199
  - app/middleware/csrf_middleware.rb
198
200
  - app/models/page.rb
199
201
  - app/models/post.rb
202
+ - app/models/product.rb
200
203
  - app/models/project.rb
201
204
  - app/models/user.rb
202
205
  - app/views/blog_home.erb
206
+ - app/views/cart_index.erb
203
207
  - app/views/cms/pages_form.erb
204
208
  - app/views/cms/pages_index.erb
205
209
  - app/views/cms/posts_form.erb
206
210
  - app/views/cms/posts_index.erb
211
+ - app/views/cms/products_form.erb
212
+ - app/views/cms/products_index.erb
207
213
  - app/views/cms/projects_form.erb
208
214
  - app/views/cms/projects_index.erb
209
215
  - app/views/dashboard.erb
@@ -216,6 +222,8 @@ files:
216
222
  - app/views/portfolio.erb
217
223
  - app/views/post.erb
218
224
  - app/views/posts/hello_world.erb
225
+ - app/views/product_show.erb
226
+ - app/views/products_index.erb
219
227
  - app/views/project.erb
220
228
  - bin/ofa
221
229
  - config.eks
@@ -229,6 +237,8 @@ files:
229
237
  - config/routes.rb
230
238
  - db/data.sqlite3
231
239
  - db/development.sqlite3
240
+ - db/migrations/20260502000000_create_products.rb
241
+ - db/target.sqlite3
232
242
  - ofa
233
243
  - public/css/cms.css
234
244
  - public/images/logo.jpg