engine2 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -3
  3. data/app/actions.coffee +87 -50
  4. data/app/app.css +2 -1
  5. data/app/engine2.coffee +37 -19
  6. data/app/modal.coffee +8 -3
  7. data/bower.json +3 -2
  8. data/conf/message.yaml +3 -0
  9. data/conf/message_pl.yaml +5 -2
  10. data/config.coffee +16 -15
  11. data/engine2.gemspec +1 -1
  12. data/lib/engine2/action.rb +51 -23
  13. data/lib/engine2/action/array.rb +94 -1
  14. data/lib/engine2/action/decode.rb +29 -3
  15. data/lib/engine2/action/delete.rb +1 -2
  16. data/lib/engine2/action/infra.rb +5 -4
  17. data/lib/engine2/action/list.rb +70 -25
  18. data/lib/engine2/action/save.rb +0 -2
  19. data/lib/engine2/action_node.rb +2 -4
  20. data/lib/engine2/core.rb +30 -21
  21. data/lib/engine2/handler.rb +5 -5
  22. data/lib/engine2/model.rb +18 -9
  23. data/lib/engine2/models/Files.rb +2 -0
  24. data/lib/engine2/scheme.rb +1 -6
  25. data/lib/engine2/templates.rb +32 -6
  26. data/lib/engine2/type_info.rb +9 -5
  27. data/lib/engine2/version.rb +1 -1
  28. data/package.json +9 -8
  29. data/views/fields/checkbox_button.slim +6 -0
  30. data/views/fields/checkbox_buttons.slim +1 -1
  31. data/views/fields/list_mbuttons.slim +9 -0
  32. data/views/fields/list_mbuttons_opt.slim +11 -0
  33. data/views/fields/list_mselect.slim +12 -0
  34. data/views/fields/scaffold.slim +1 -1
  35. data/views/fields/typeahead_picker.slim +8 -5
  36. data/views/infra/inspect.slim +19 -16
  37. data/views/scaffold/fields.slim +3 -1
  38. data/views/scaffold/search.slim +2 -2
  39. data/views/scaffold/search_collapse.slim +2 -2
  40. data/views/scaffold/search_tabs.slim +2 -2
  41. data/views/search_fields/date.slim +20 -0
  42. data/views/search_fields/list_mbuttons.slim +12 -0
  43. data/views/search_fields/typeahead_picker.slim +4 -3
  44. metadata +11 -5
@@ -57,6 +57,10 @@ module Engine2
57
57
  def invoke handler
58
58
  {entries: get_query.limit(200).load_all}
59
59
  end
60
+
61
+ def order *fields
62
+ @query = get_query.order *fields
63
+ end
60
64
  end
61
65
 
62
66
  class TypeAheadAction < DecodeAction
@@ -71,17 +75,39 @@ module Engine2
71
75
  @limit = lmt
72
76
  end
73
77
 
78
+ def get_limit
79
+ @limit
80
+ end
81
+
82
+ def get_case_insensitive
83
+ @case_insensitive
84
+ end
85
+
74
86
  def case_insensitive
75
87
  @case_insensitive = true
76
88
  end
77
89
 
90
+ def order *fields
91
+ @query = get_query.order *fields
92
+ end
93
+
78
94
  def invoke handler
95
+ model = assets[:model]
79
96
  if query = handler.params[:query]
80
- condition = @meta[:decode_fields].map{|f|f.like("%#{query}%", case_insensitive: @case_insensitive)}.reduce{|q, f| q | f}
81
- {entries: get_query.where(condition).limit(@limit).load_all}
97
+ fields = @meta[:decode_fields] || static.meta[:decode_fields]
98
+
99
+ entries = if query.to_s.empty?
100
+ get_query
101
+ else
102
+ table_name = model.table_name
103
+ condition = fields.map{|f|table_name.q(f).like("%#{query}%", case_insensitive: @case_insensitive || static.get_case_insensitive)}.reduce{|q, f| q | f}
104
+ get_query.where(condition)
105
+ end.limit(@limit || static.get_limit).load_all
106
+
107
+ {entries: entries}
82
108
  else
83
109
  handler.permit id = handler.params[:id]
84
- record = get_query.load Hash[assets[:model].primary_keys.zip(split_keys(id))]
110
+ record = get_query.unordered.load Hash[model.primary_keys_qualified.zip(split_keys(id))]
85
111
  # handler.halt_not_found(LOCS[:no_entry]) unless record
86
112
  {entry: record}
87
113
  end
@@ -61,5 +61,4 @@ module Engine2
61
61
  invoke_delete_db(handler, ids)
62
62
  end
63
63
  end
64
-
65
- end
64
+ end
@@ -24,7 +24,7 @@ module Engine2
24
24
 
25
25
  define_node :inspect_modal, InspectModalAction do
26
26
  access! &:logged_in?
27
- define_node :inspect, WebSocketAction.inherit do
27
+ define_node :"inspect_#{SETTINGS[:name]}", WebSocketAction.inherit do
28
28
  self.* do
29
29
  @action_type = :inspect
30
30
 
@@ -112,7 +112,8 @@ module Engine2
112
112
  temp.close
113
113
  rackname = File.basename(temp.path)
114
114
  info = node.parent.*.model.type_info[node.parent.*.field]
115
- File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
115
+ FileUtils.cp(temp.path, "#{info[:store][:upload]}/#{rackname}") # File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
116
+ FileUtils.rm(temp.path)
116
117
  {rackname: rackname}
117
118
  end
118
119
  end
@@ -233,9 +234,9 @@ module Engine2
233
234
  {user: user ? user.to_hash : nil}
234
235
  end
235
236
 
236
- def login_meta show_login_otion = 'false', &blk
237
+ def login_meta menu_properties = {show: 'false'}, &blk
237
238
  node.login_form.* &blk
238
- menu(:menu).modify_option :login_form, show: show_login_otion
239
+ menu(:menu).modify_option :login_form, menu_properties
239
240
  node.parent.login_form.* &blk
240
241
  end
241
242
  end
@@ -34,6 +34,13 @@ module Engine2
34
34
  query.where(name => Sequel.string_to_date(value))
35
35
  end
36
36
  },
37
+ datetime: lambda{|query, name, value, type_info, hash|
38
+ if value.is_a? Hash
39
+ DefaultFilters[:date].(query, name, value, type_info, hash)
40
+ else
41
+ query.where(:date.sql_function(name) => Sequel.string_to_date(value))
42
+ end
43
+ },
37
44
  integer: lambda{|query, name, value, type_info, hash|
38
45
  if value.is_a? Hash
39
46
  from, to = value[:from], value[:to]
@@ -82,6 +89,10 @@ module Engine2
82
89
  super
83
90
  end
84
91
 
92
+ def page_frame handler, entries
93
+ entries
94
+ end
95
+
85
96
  def invoke handler
86
97
  params = handler.params
87
98
  model = assets[:model]
@@ -89,31 +100,30 @@ module Engine2
89
100
 
90
101
  if search = params[:search]
91
102
  query = list_search(query, handler, search)
103
+ elsif @filters || static.filters
104
+ static.filters.to_h.merge(@filters.to_h).each do |name, filter|
105
+ query = filter.(handler, query, {})
106
+ handler.permit query
107
+ end
92
108
  end
93
109
 
94
110
  count = query.count if lookup(:config, :use_count)
95
111
 
96
- if order_str = params[:order]
97
- order = order_str.to_sym
112
+ if order = params[:order]
113
+ order = order.to_sym
98
114
  handler.permit lookup(:fields, order, :sort)
99
-
100
- if order_blk = (@orders && @orders[order]) || (dynamic? && (static.orders && static.orders[order]))
101
- query = order_blk.(handler, query)
102
- else
103
- order = model.table_name.q(order) if model.type_info[order]
104
- query = query.order(order)
105
- end
106
-
107
- query = query.reverse if params[:asc] == "true"
115
+ query = list_order(query, handler, order, params[:asc] == "true")
116
+ elsif order = @default_order_field || static.default_order_field
117
+ query = list_order(query, handler, order, true)
108
118
  end
109
119
 
110
120
  per_page = lookup(:config, :per_page)
111
121
  page = params[:page].to_i
112
- handler.permit page >= 0 && page < 1000
122
+ handler.permit page >= 0 && page < 1000000
113
123
 
114
124
  query = query.limit(per_page, page)
115
125
 
116
- res = {entries: query.load_all}
126
+ res = {entries: page_frame(handler, query.load_all)}
117
127
  res[:count] = count if count
118
128
  res
119
129
  end
@@ -123,24 +133,60 @@ module Engine2
123
133
  model = assets[:model]
124
134
  sfields = lookup(:search_field_list)
125
135
  handler.permit sfields
126
- hash.each_pair do |name, value|
127
- handler.permit name = sfields.find{|sf|sf.to_sym == name}
128
136
 
137
+ filters = @filters || static.filters ? static.filters.to_h.merge(@filters.to_h) : {}
138
+
139
+ sfields.each do |name|
129
140
  type_info = model.find_type_info(name)
130
- query = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
131
- filter.(handler, query, hash)
132
- elsif filter = DefaultFilters[type_info[:otype]]
133
- name = model.type_info[name] ? model.table_name.q(name) : Sequel.expr(name)
134
- filter.(query, name, value, type_info, hash)
141
+ name = name.to_sym
142
+ filter = filters[name]
143
+ if !(value = hash[name]).nil? # use key?
144
+ query = if filter
145
+ filter.(handler, query, hash)
146
+ elsif filter = DefaultFilters[type_info[:otype]]
147
+ name = model.type_info[name] ? model.table_name.q(name) : Sequel.expr(name)
148
+ filter.(query, name, value, type_info, hash)
149
+ else
150
+ raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
151
+ end
152
+ handler.permit query
135
153
  else
136
- raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
154
+ if filter
155
+ query = filter.(handler, query, hash)
156
+ handler.permit query
157
+ end
137
158
  end
138
-
139
- handler.permit query
140
159
  end
160
+
161
+ # hash.each_pair do |name, value|
162
+ # handler.permit name = sfields.find{|sf|sf.to_sym == name}
163
+ # type_info = model.find_type_info(name)
164
+ # query = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
165
+ # filter.(handler, query, hash)
166
+ # elsif filter = DefaultFilters[type_info[:otype]]
167
+ # name = model.type_info[name] ? model.table_name.q(name) : Sequel.expr(name)
168
+ # filter.(query, name, value, type_info, hash)
169
+ # else
170
+ # raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
171
+ # end
172
+ # handler.permit query
173
+ # end
174
+
141
175
  query
142
176
  end
143
177
 
178
+ def list_order query, handler, order, asc
179
+ model = assets[:model]
180
+ query = if order_blk = (@orders && @orders[order]) || (dynamic? && (static.orders && static.orders[order]))
181
+ order_blk.(handler, query)
182
+ else
183
+ order = model.table_name.q(order) if model.type_info[order]
184
+ query.order(order)
185
+ end
186
+
187
+ asc ? query : query.reverse
188
+ end
189
+
144
190
  def list_context query, handler
145
191
  query
146
192
  end
@@ -165,7 +211,7 @@ module Engine2
165
211
  def pre_run
166
212
  super
167
213
  menu(:panel_menu).option_at 0, :close, icon: "remove"
168
- panel_title "#{:list.icon} #{LOCS[assets[:assoc][:name]]}"
214
+ panel_title "#{assets[:model].model_icon.icon} #{LOCS[assets[:assoc][:name]]}"
169
215
  end
170
216
 
171
217
  def list_context query, handler
@@ -285,4 +331,3 @@ module Engine2
285
331
  end
286
332
  end
287
333
  end
288
-
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Engine2
5
-
6
5
  class SaveAction < Action
7
6
  include ActionSaveSupport
8
7
  end
@@ -26,5 +25,4 @@ module Engine2
26
25
  self.validate_only = true
27
26
  action_type :star_to_many_field_approve
28
27
  end
29
-
30
28
  end
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Engine2
5
-
6
5
  class ActionNode < BasicObject
7
6
  ACCESS_FORBIDDEN ||= ->h{false}
8
7
  attr_reader :parent, :name, :number, :nodes, :recheck_access
@@ -201,7 +200,7 @@ module Engine2
201
200
  true
202
201
  end
203
202
 
204
- ::Kernel::puts "ACTION NODES: #{ActionNode.count}, Panels: #{panels}, Time: #{::Time.now - time}, Thefts: #{thefts}"
203
+ ::Kernel::puts "ACTION NODES: #{ActionNode.count}, Panels: #{panels}, Thefts: #{thefts}, Time: #{::Time.now - time}"
205
204
  end
206
205
 
207
206
  def p *args
@@ -209,7 +208,6 @@ module Engine2
209
208
  end
210
209
  end
211
210
 
212
-
213
211
  class ActionNodeBundle
214
212
  def initialize node, node_names
215
213
  @node = node
@@ -220,4 +218,4 @@ module Engine2
220
218
  @node_names.each{|an| @node[an].__send__(name, *args, &blk)}
221
219
  end
222
220
  end
223
- end
221
+ end
@@ -126,6 +126,10 @@ class String
126
126
  s
127
127
  end
128
128
  end
129
+
130
+ def escape_html
131
+ Rack::Utils.escape_html(self)
132
+ end
129
133
  end
130
134
 
131
135
  class Symbol
@@ -138,12 +142,18 @@ class Symbol
138
142
  end
139
143
  end
140
144
 
145
+ def loc
146
+ Engine2::LOCS[self]
147
+ end
148
+
141
149
  def q col
142
150
  col.qualify self
143
151
  end
144
152
 
145
- def loc
146
- Engine2::LOCS[self]
153
+ def html body = '', attrs = {}
154
+ element = self.to_s
155
+ attrs = attrs.map{|k, v| "#{k}=\"#{v}\""}.join(" ")
156
+ "<#{element} #{attrs}>#{body}</#{element}>"
147
157
  end
148
158
  end
149
159
 
@@ -174,7 +184,7 @@ class Sequel::Database
174
184
  attr_accessor :models, :default_schema
175
185
 
176
186
  def cache_file
177
- "#{Engine2::SETTINGS.path_for(:db_path)}/#{opts[:orig_opts][:name]}.dump"
187
+ "#{Engine2::SETTINGS.path_for(:db_path)}/#{opts[:orig_opts][:name]}.schema_cache"
178
188
  end
179
189
 
180
190
  def load_schema_cache_from_file
@@ -282,7 +292,7 @@ module E2Model
282
292
  next if info[:primary_key] && !model.natural_key
283
293
 
284
294
  value = values[name].to_s
285
- value.strip! unless info[:dont_strip]
295
+ value.strip! unless value.frozen? || info[:dont_strip]
286
296
  if value.empty?
287
297
  if req = info[:required]
288
298
  errors.add(name, req[:message]) if !req[:if] || req[:if].(self)
@@ -392,7 +402,6 @@ module E2Model
392
402
  else
393
403
  select(*pk.map{|k| model.table_name.q(k)})
394
404
  end
395
-
396
405
  end
397
406
 
398
407
  def extract_select sel, al = nil, &blk
@@ -413,41 +422,41 @@ module E2Model
413
422
 
414
423
  def setup_query fields
415
424
  joins = {}
416
- type_info = model.type_info
417
425
  model_table_name = model.table_name
418
426
 
419
427
  select = @opts[:select].map do |sel|
420
428
  extract_select sel do |table, name, aliaz|
421
- info = if table
429
+ mdl = if table
422
430
  if table == model_table_name
423
431
  model
424
432
  else
425
433
  assoc = model.many_to_one_associations[table] || model.many_to_many_associations[table]
426
434
  raise Engine2::E2Error.new("Association #{table} not found for model #{model}") unless assoc
427
435
  assoc.associated_class
428
- end.type_info
436
+ end
429
437
  else
430
- type_info
438
+ model
431
439
  end
432
440
 
433
- table ||= model_table_name
434
- if table == model_table_name
441
+ mdl_table_name = mdl.table_name
442
+ table ||= mdl_table_name
443
+ if mdl_table_name == model_table_name
435
444
  fields << name
436
445
  else
437
446
  fields << table.q(name)
438
- joins[table] ||= model.many_to_one_associations[table] || model.many_to_many_associations[table]
447
+ joins[mdl_table_name] ||= model.many_to_one_associations[table] || model.many_to_many_associations[table]
439
448
  end
440
449
 
441
- f_info = info[name]
442
- raise Engine2::E2Error.new("Column #{name} not found for table #{table || model_table_name}") unless f_info
450
+ f_info = mdl.type_info[name]
451
+ raise Engine2::E2Error.new("Column #{name} not found for table #{table}") unless f_info
443
452
  if f_info[:dummy]
444
453
  nil
445
454
  else
446
- qname = table.q(name)
447
- if table != model_table_name
448
- Sequel.alias_columns_in_joins ? qname.as(:"#{table}__#{name}") : qname
449
- else
455
+ qname = mdl_table_name.q(name)
456
+ if table == model_table_name
450
457
  qname
458
+ else
459
+ Sequel.alias_columns_in_joins ? qname.as(:"#{table}__#{name}") : qname
451
460
  end
452
461
  end
453
462
  end
@@ -488,7 +497,6 @@ module Sequel
488
497
  @error = error
489
498
  end
490
499
  end
491
-
492
500
  end
493
501
 
494
502
  module Engine2
@@ -501,7 +509,8 @@ module Engine2
501
509
  model_path: 'models',
502
510
  view_path: 'views',
503
511
  asset_path: 'assets',
504
- conf_path: 'conf'
512
+ conf_path: 'conf',
513
+ log_path: 'log'
505
514
  }
506
515
 
507
516
  def SETTINGS.path_for path
@@ -549,10 +558,10 @@ module Engine2
549
558
  load "#{Engine2::SETTINGS[:app_path]}/boot.rb"
550
559
 
551
560
  Sequel::DATABASES.each &:load_schema_cache_from_file
552
- @model_boot_blk.() if @model_boot_blk
553
561
  load 'engine2/models/Files.rb'
554
562
  load 'engine2/models/UserInfo.rb'
555
563
  Dir["#{Engine2::SETTINGS.path_for(:model_path)}/*"].each{|m| load m}
564
+ @model_boot_blk.() if @model_boot_blk
556
565
  puts "MODELS: #{Sequel::DATABASES.reduce(0){|s, d|s + d.models.size}}, Time: #{Time.now - t}"
557
566
  Sequel::DATABASES.each do |db|
558
567
  db.dump_schema_cache_to_file
@@ -119,16 +119,16 @@ module Engine2
119
119
  slim name.to_sym
120
120
  end
121
121
 
122
- production = environment == :production
123
-
124
- set :slim, pretty: !production, sort_attrs: false
125
- set :sessions, expire_after: 3600, httponly: production # , secure: production
122
+ set :slim, pretty: !production?, sort_attrs: false
123
+ unless production? # use Engine2::SETTINGS[:reloading] ?
124
+ set :sessions, expire_after: 3600
125
+ # set :session_store, Rack::Session::Pool
126
+ end
126
127
 
127
128
  helpers do
128
129
  def find_template(views, name, engine, &block)
129
130
  views.each{|v| super(v, name, engine, &block)}
130
131
  end
131
132
  end
132
-
133
133
  end
134
134
  end