ezframe 0.0.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +1 -1
  4. data/asset/css/materialize.min.css +13 -0
  5. data/asset/css/style.css +3 -0
  6. data/asset/html/index.html +1 -0
  7. data/{app_template/asset/image/favicon.ico → asset/image/c_e.ico} +0 -0
  8. data/asset/js/ezframe.js +387 -0
  9. data/exe/check_column_yml +64 -0
  10. data/exe/console +2 -2
  11. data/exe/{create_table.rb → create_table} +7 -4
  12. data/exe/dbmigrate +174 -0
  13. data/exe/html2ruby +61 -0
  14. data/ezframe.gemspec +10 -8
  15. data/lib/ezframe.rb +9 -3
  16. data/lib/ezframe/auth.rb +50 -31
  17. data/lib/ezframe/column_set.rb +314 -103
  18. data/lib/ezframe/column_type.rb +456 -99
  19. data/lib/ezframe/config.rb +27 -6
  20. data/lib/ezframe/controller.rb +41 -38
  21. data/lib/ezframe/database.rb +171 -52
  22. data/lib/ezframe/editor_common.rb +74 -0
  23. data/lib/ezframe/email.rb +34 -0
  24. data/lib/ezframe/ezlog.rb +40 -0
  25. data/lib/ezframe/ht.rb +42 -17
  26. data/lib/ezframe/html.rb +47 -31
  27. data/lib/ezframe/japanese_utils.rb +15 -0
  28. data/lib/ezframe/jquery-ui.rb +29 -0
  29. data/lib/ezframe/loader.rb +4 -4
  30. data/lib/ezframe/main_editor.rb +19 -0
  31. data/lib/ezframe/main_page_kit.rb +226 -0
  32. data/lib/ezframe/materialize.rb +10 -14
  33. data/lib/ezframe/message.rb +46 -0
  34. data/lib/ezframe/page_base.rb +59 -71
  35. data/lib/ezframe/route.rb +126 -0
  36. data/lib/ezframe/server.rb +16 -5
  37. data/lib/ezframe/single_page_editor.rb +22 -0
  38. data/lib/ezframe/single_page_kit.rb +199 -0
  39. data/lib/ezframe/sub_editor.rb +25 -0
  40. data/lib/ezframe/sub_page_kit.rb +213 -0
  41. data/lib/ezframe/template.rb +5 -4
  42. data/lib/ezframe/util.rb +45 -23
  43. data/lib/ezframe/version.rb +1 -1
  44. metadata +74 -34
  45. data/.rubocop.yml +0 -44
  46. data/app_template/asset/js/ezframe.js +0 -288
  47. data/app_template/config.ru +0 -10
  48. data/app_template/config/generic.yml +0 -3
  49. data/app_template/config/materialize.yml +0 -5
  50. data/app_template/pages/basic.rb +0 -5
  51. data/exe/setup.rb +0 -15
  52. data/lib/ezframe/editor.rb +0 -188
  53. data/lib/ezframe/model.rb +0 -52
  54. data/lib/ezframe/page_kit.rb +0 -63
@@ -3,23 +3,40 @@ module Ezframe
3
3
  class << self
4
4
  attr_accessor :value_h
5
5
 
6
+ def init(dir = "./config")
7
+ load_files(dir)
8
+ end
9
+
6
10
  def load_files(dir)
7
11
  unless @value_h
8
- Dir["#{dir}/*.yml"].each do |file|
9
- load_one_file(file)
12
+ load_dir(dir)
13
+ rack_env = ENV['RACK_ENV']
14
+ env_dir = "#{dir}/#{rack_env}"
15
+ if rack_env && File.directory?(env_dir)
16
+ load_dir(env_dir)
10
17
  end
11
18
  end
12
19
  end
13
20
 
21
+ def load_dir(dir)
22
+ Dir["#{dir}/*.yml"].each do |file|
23
+ load_one_file(file)
24
+ end
25
+ end
26
+
14
27
  def load_one_file(filename)
28
+ instr = File.open(filename, &:read)
29
+ if instr.index("\#{")
30
+ instr = Template.fill_in_text(instr)
31
+ end
15
32
  begin
16
- yaml = YAML.load_file(filename)
17
- rescue
18
- mylog("YAML load error: #{filename}")
33
+ yaml = YAML.load(instr, symbolize_names: true)
34
+ rescue => e
35
+ EzLog.info("YAML load error: #{filename}:#{e}")
19
36
  return
20
37
  end
21
38
  @value_h ||={}
22
- @value_h.update(yaml.recursively_symbolize_keys) if yaml.length>0
39
+ @value_h.update(yaml) if yaml.length>0 # .recursively_symbolize_keys
23
40
  end
24
41
 
25
42
  def [](k)
@@ -31,6 +48,10 @@ module Ezframe
31
48
  @value_h[k]=v
32
49
  end
33
50
 
51
+ def delete(k)
52
+ @value_h.delete(k) if @value_h[k]
53
+ end
54
+
34
55
  def inspect
35
56
  @value_h.inspect
36
57
  end
@@ -1,60 +1,63 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  module Ezframe
4
- class Boot
3
+ class Controller
5
4
  class << self
5
+ def init
6
+ Config.init
7
+ ColumnSets.init
8
+ DB.init
9
+ Message.init
10
+ Auth.init if Config[:auth]
11
+ end
12
+
6
13
  def exec(request, response)
7
14
  @request = request
8
- Config.load_files("./config")
9
- Model.init
10
- model = Model.get_clone
11
- Auth.init_warden if defined?(Warden)
12
- @request.env["model"] = model
15
+ page_instance, method, url_params, class_opts = Route::choose(request)
13
16
 
14
- mylog("exec: path=#{request.path_info} params=#{request.params}")
15
- klass, method = PageBase::decide_route(request.path_info)
16
- unless klass
17
- response.status = 404
18
- response['Content-Type'] = 'text/html; charset=utf-8'
19
- response.body = [ Html.convert(Ht.p("file not found")) ]
17
+ EzLog.debug("Controller.exec: path=#{request.path_info}, params=#{request.params}, class=#{page_instance.class}, method=#{method}, url_params=#{url_params}, class_opts=#{class_opts}")
18
+ if !page_instance || page_instance == 404
19
+ file_not_found(response)
20
20
  return
21
21
  end
22
- method = "default" if !method || method=="undefined"
23
- page = klass.new(request, model)
24
- if request.post?
25
- method_full_name = "public_#{method}_post"
26
- else
27
- method_full_name = "public_#{method}_page"
28
- end
29
- if page.auth
22
+ @request.env["url_params"] = url_params
23
+ opt_auth = class_opts[:auth]
24
+ @session = @request.env['rack.session']
25
+ if !@session[:user] && Config[:auth] && (!opt_auth || opt_auth != "disable")
26
+ EzLog.debug("authenticate!")
30
27
  warden.authenticate!
28
+ EzLog.info "Controller.exec: warden.options = #{@request.env['warden.options']}"
31
29
  end
32
- # request.env["rack.session"]["kamatest"]="usable"
33
- # mylog "method: #{klass}.#{method_full_name}"
34
- #mylog "rack.session.id=#{request.env['rack.session'].id}"
35
- mylog "rack.session.keys=#{request.env['rack.session'].keys}"
36
- #mylog "warden=#{request.env['warden'].inspect}"
37
- mylog "klass=#{klass}, method=#{method_full_name}"
38
- body = if page.respond_to?(method_full_name)
39
- page.send(method_full_name)
40
- else
41
- mylog "no such method: #{method_full_name}"
42
- page.public_default_page
43
- end
30
+ # session["in_controller"] = "set in controller"
31
+ EzLog.debug "rack.session.keys=#{@session.keys}" if @session
32
+ page_instance.set_request(@request)
33
+ body = page_instance.send(method)
34
+
35
+ # 戻り値によるレスポンス生成
44
36
  if body.is_a?(Hash) || body.is_a?(Array)
45
- response.body = [ JSON.generate(body) ]
37
+ # EzLog.debug("Controller: body = #{body}")
38
+ json = JSON.generate(body)
39
+ response.body = [ json ]
46
40
  response['Content-Type'] = 'application/json; charset=utf-8'
47
41
  else
48
42
  response.body = [ body ]
49
43
  response['Content-Type'] = 'text/html; charset=utf-8'
50
44
  end
51
45
  response.status = 200
46
+ # EzLog.debug("Controller.exec: response.body=#{response.body}")
52
47
  end
53
48
 
54
- # def file_not_found(response)
55
- # response.body = ['path not found']
56
- # response.status = 404
57
- # end
49
+ def file_not_found(response)
50
+ response.status = 404
51
+ response['Content-Type'] = 'text/html; charset=utf-8'
52
+ template_file = ("#{Config[:template_dir]}/404.html")
53
+ # puts template_file
54
+ if File.exist?(template_file)
55
+ body = File.read(template_file)
56
+ else
57
+ body = Html.convert(Ht.p("file not found"))
58
+ end
59
+ response.body = [ body ]
60
+ end
58
61
 
59
62
  def warden
60
63
  @request.env["warden"]
@@ -1,62 +1,181 @@
1
1
  # frozen_string_literal: true
2
- require "logger"
3
-
4
2
  module Ezframe
5
- class Database
6
- attr_accessor :sequel
7
-
8
- def initialize(dbfile = nil)
9
- @dbfile = dbfile
10
- connect
11
- end
12
-
13
- def connect
14
- @dbfile ||= ENV["EZFRAME_DB"] || Config[:database] || "sqlite://db/devel.sqlite"
15
- puts "Database.connect: dbfile=#{@dbfile}"
16
- @sequel = Sequel.connect(@dbfile, loggers: [Logger.new($stdout)])
17
- end
18
-
19
- def exec(sql)
20
- @sequel.run(sql)
21
- end
22
-
23
- def dataset(table_name)
24
- @sequel[table_name.to_sym]
25
- end
26
-
27
- def create_table(table_name, dbtype_h)
28
- %w[id created_at updated_at].each do |key|
29
- dbtype_h.delete(key.to_sym)
30
- end
31
- # puts "create_table: #{table_name}"
32
- if @dbfile.index("postgres")
33
- @sequel.create_table(table_name) do
34
- serial :id
35
- dbtype_h.each do |key, dbtype|
36
- column(key, dbtype)
3
+ class DB
4
+ class << self
5
+ attr_accessor :sequel, :pool
6
+
7
+ def init(dbfile = nil, opts = {})
8
+ @dbfile = dbfile || ENV["EZFRAME_DB"] || Config[:database]
9
+ unless @dbfile
10
+ raise "database settings error: dbfile=#{Config[:database]}"
11
+ end
12
+ #if Config[:use_connection_pool] || opts[:use_connection_pool]
13
+ #@pool = Sequel::ConnectionPool.new(max_connections: 10) do
14
+ # Sequel.connect(@dbfile, loggers: [EzLog])
15
+ #end
16
+ #else
17
+ connect(@dbfile)
18
+ #end
19
+ end
20
+
21
+ def connect(dbfile = nil)
22
+ dbfile ||= @dbfile
23
+ @sequel = Sequel.connect(dbfile, EzLogs: [EzLog])
24
+ return @sequel
25
+ end
26
+
27
+ def disconnect
28
+ @sequel.disconnect
29
+ end
30
+
31
+ def get_conn
32
+ if @pool
33
+ @pool.hold {|conn| return conn }
34
+ else
35
+ @sequel
36
+ end
37
+ end
38
+
39
+ def exec(sql, first: nil)
40
+ conn = get_conn
41
+ if first
42
+ return conn[sql].first
43
+ else
44
+ return conn[sql].all
45
+ end
46
+ end
47
+
48
+ def run(sql)
49
+ conn = get_conn
50
+ conn.run(sql)
51
+ end
52
+
53
+ def dataset(table_name)
54
+ @sequel[table_name.to_sym]
55
+ end
56
+
57
+ class JointHash < Hash
58
+ def initialize(default_table, values = {})
59
+ @default_table = default_table
60
+ self.update(values)
61
+ end
62
+
63
+ def []=(key, value)
64
+ super(key.to_s, value)
65
+ end
66
+
67
+ def [](key)
68
+ key = key.to_s
69
+ return fetch(key) if has_key?(key)
70
+ alt_key = "#{@default_table}.#{key}"
71
+ return fetch(alt_key) if has_key?(alt_key)
72
+ return nil
73
+ end
74
+ end
75
+
76
+ # テーブルを連結して、全てのデータを返す。
77
+ def get_join_table(structure, opts = {})
78
+ col_h = {}
79
+ reverse_col_h = {}
80
+ query_a = []
81
+ table_a = []
82
+ prefix="_x_"
83
+ structure[:column_list].each_with_index do |k, i|
84
+ key = "#{prefix}#{i+1}"
85
+ col_h[k.to_sym] = key.to_sym
86
+ reverse_col_h[key.to_sym] = k
87
+ query_a.push "#{k} AS #{key}"
88
+ end
89
+ tables = structure[:tables].clone
90
+ join_cond = structure[:join_condition]
91
+ tb = tables.shift
92
+ table_part = [ tb ]
93
+ tables.each do |table|
94
+ cond = join_cond[table.to_sym]
95
+ if cond
96
+ table_part.push " LEFT JOIN #{table} ON #{cond}"
97
+ else
98
+ table_part.push " LEFT JOIN #{table} ON #{tb}.#{table} = #{table}.id"
37
99
  end
38
- column(:created_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
39
- column(:updated_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
40
- end
41
- else
42
- @sequel.create_table(table_name) do
43
- primary_key :id, auto_increment: true
44
- dbtype_h.each do |key, dbtype|
45
- column(key, dbtype)
100
+ end
101
+ sql = "SELECT #{query_a.join(', ')} FROM #{table_part.join(' ')}"
102
+ sql += " WHERE #{opts[:where]}" if opts[:where]
103
+ sql += " ORDER BY #{opts[:order]}" if opts[:order]
104
+ sql += " LIMIT #{opts[:limit]}" if opts[:limit]
105
+ data_a = self.exec(sql)
106
+ res_a = []
107
+ data_a.each do |data|
108
+ new_data = JointHash.new(tb)
109
+ data.each do |k, v|
110
+ orig_key = reverse_col_h[k.to_sym]
111
+ next unless orig_key
112
+ new_data[orig_key] = v
46
113
  end
47
- column(:created_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
48
- column(:updated_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
114
+ res_a.push(new_data)
49
115
  end
116
+ return res_a
117
+ end
118
+
119
+ # テーブル生成
120
+ def create_table(table_name, dbtype_h)
121
+ %w[id created_at updated_at deleted_at].each do |key|
122
+ dbtype_h.delete(key.to_sym)
123
+ end
124
+ # puts "create_table: #{table_name}"
125
+ if @dbfile.index("postgres")
126
+ @sequel.create_table(table_name) do
127
+ primary_key :id, identity: true
128
+ dbtype_h.each do |key, dbtype|
129
+ column(key, dbtype)
130
+ end
131
+ column(:created_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
132
+ column(:updated_at, :timestamp)
133
+ column(:deleted_at, :timestamp)
134
+ end
135
+ else
136
+ @sequel.create_table(table_name) do
137
+ primary_key :id, auto_increment: true
138
+ dbtype_h.each do |key, dbtype|
139
+ column(key, dbtype)
140
+ end
141
+ column(:created_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
142
+ column(:updated_at, :timestamp)
143
+ column(:deleted_at, :timestamp)
144
+ end
145
+ end
146
+ end
147
+
148
+ def insert(table_name, val_h)
149
+ dataset(table_name).insert(val_h)
150
+ end
151
+
152
+ def update(dataset, id, val_h)
153
+ val_h.update({ updated_at: Time.now })
154
+ dataset.where(id: id).update(val_h)
155
+ end
156
+
157
+ def delete(dataset, id)
158
+ dataset.where(id: id).update({ deleted_at: Time.now })
50
159
  end
51
- end
52
-
53
- def insert(table_name, val_h)
54
- dataset(table_name).insert(val_h)
55
160
  end
56
161
 
57
- def update(dataset, val_h)
58
- val_h.update({ updated_at: Time.now() })
59
- dataset.update(val_h)
60
- end
162
+ class Cache
163
+ class << self
164
+
165
+ def [](table)
166
+ @store ||= {}
167
+ dataset = DB.dataset(table.to_sym)
168
+ # EzLog.debug("DB::Cache: #{table}")
169
+ unless @store[table.to_sym]
170
+ data_a = dataset.where(deleted_at: nil).all
171
+ h = {}
172
+ data_a.each {|data| h[data[:id]] = data }
173
+ @store[table.to_sym] = h
174
+ end
175
+ # EzLog.debug(@store[table.to_sym])
176
+ return @store[table.to_sym]
177
+ end
178
+ end
179
+ end
61
180
  end
62
181
  end
@@ -0,0 +1,74 @@
1
+ module Ezframe
2
+ module EditorCommon
3
+ def get_id(class_name = nil)
4
+ class_name ||= @class_snake
5
+ params = @request.env['url_params']
6
+ return nil unless params
7
+ # EzLog.info "get_id: #{params.inspect}, #{class_name}"
8
+ return params[class_name.to_sym]
9
+ end
10
+
11
+ # 新規データの生成
12
+ def create_data(form)
13
+ @column_set.clear
14
+ @column_set[:id].value = id = @column_set.create(form)
15
+ return id
16
+ end
17
+
18
+ # データの更新
19
+ def update_data(id, form)
20
+ @column_set.update(id, form)
21
+ end
22
+
23
+ def make_form(url, child)
24
+ return Ht.form(ezload: "command=set_validation:validate_url=#{url}", child: child)
25
+ end
26
+
27
+ # 新規登録ボタンの生成
28
+ def make_create_button(event = nil)
29
+ event ||= "on=click:url=#{make_base_url(@id)}/create"
30
+ return Ht.button(id: "#{@class_snake}-create-button", class: %[btn], child: [Ht.icon("add"), Message[:create_button_label]], ezevent: event)
31
+ end
32
+
33
+ # 編集ボタンの生成
34
+ def make_edit_button(event = nil)
35
+ event ||= "on=click:url=#{make_base_url(@id)}/edit"
36
+ return Ht.button(class: %w[btn], ezevent: event, child: [ Ht.icon("edit"), Message[:edit_button_label]])
37
+ end
38
+
39
+ # 削除ボタンの生成
40
+ def make_delete_button(event = nil)
41
+ event ||= "on=click:url=#{make_base_url(@id)}/delete"
42
+ return Ht.button(class: %w[btn right red], ezevent: event, child: [Ht.icon("delete"), Message[:delete_button_label]])
43
+ end
44
+
45
+ # キャンセルボタンの生成
46
+ def make_cancel_button(event = nil)
47
+ event ||= "on=click:url=#{make_base_url(@id)}/detail:cancel=true:with=form"
48
+ return Ht.button(class: %w[btn red], child: [Ht.icon("cancel"), Message[:cancel_button_label]], ezevent: event)
49
+ end
50
+
51
+ # 値の更新
52
+ # def update_value
53
+ # form = @event[:form]
54
+ # @column_set.update(get_id, form)
55
+ # end
56
+
57
+ # ラベル付きで1カラムのviewを表示
58
+ def show_label_view(key)
59
+ col = @column_set[key]
60
+ Ht.span([Ht.small(col.label), col.view(force: true)])
61
+ end
62
+
63
+ # ラベル付きで1カラムのformを表示
64
+ def show_label_edit(key)
65
+ col = @column_set[key]
66
+ Ht.span([Ht.small(col.label), col.form(force: true)])
67
+ end
68
+
69
+ # エラーメッセージだけを表示するページを生成
70
+ def show_message_page(title, body)
71
+ return show_base_template(title: title, body: Html.convert(body))
72
+ end
73
+ end
74
+ end