ezframe 0.0.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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