engine2 1.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.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/Rakefile +138 -0
- data/conf/message.yaml +93 -0
- data/conf/message_pl.yaml +93 -0
- data/engine2.gemspec +34 -0
- data/lib/engine2.rb +34 -0
- data/lib/engine2/action.rb +217 -0
- data/lib/engine2/core.rb +572 -0
- data/lib/engine2/handler.rb +134 -0
- data/lib/engine2/meta.rb +969 -0
- data/lib/engine2/meta/decode_meta.rb +110 -0
- data/lib/engine2/meta/delete_meta.rb +73 -0
- data/lib/engine2/meta/form_meta.rb +144 -0
- data/lib/engine2/meta/infra_meta.rb +292 -0
- data/lib/engine2/meta/link_meta.rb +133 -0
- data/lib/engine2/meta/list_meta.rb +284 -0
- data/lib/engine2/meta/save_meta.rb +63 -0
- data/lib/engine2/meta/view_meta.rb +22 -0
- data/lib/engine2/model.rb +390 -0
- data/lib/engine2/models/Files.rb +38 -0
- data/lib/engine2/models/UserInfo.rb +24 -0
- data/lib/engine2/post_bootstrap.rb +83 -0
- data/lib/engine2/pre_bootstrap.rb +27 -0
- data/lib/engine2/scheme.rb +202 -0
- data/lib/engine2/templates.rb +229 -0
- data/lib/engine2/type_info.rb +342 -0
- data/lib/engine2/version.rb +9 -0
- data/public/assets/javascripts.js +13 -0
- data/public/assets/styles.css +4 -0
- data/public/css/angular-motion.css +1022 -0
- data/public/css/angular-ui-tree.min.css +1 -0
- data/public/css/app.css +196 -0
- data/public/css/bootstrap-additions.css +1560 -0
- data/public/css/bootstrap.min.css +11 -0
- data/public/css/font-awesome.min.css +4 -0
- data/public/favicon.ico +0 -0
- data/public/fonts/FontAwesome.otf +0 -0
- data/public/fonts/fontawesome-webfont.eot +0 -0
- data/public/fonts/fontawesome-webfont.svg +655 -0
- data/public/fonts/fontawesome-webfont.ttf +0 -0
- data/public/fonts/fontawesome-webfont.woff +0 -0
- data/public/fonts/fontawesome-webfont.woff2 +0 -0
- data/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/fonts/glyphicons-halflings-regular.svg +288 -0
- data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/public/images/file.png +0 -0
- data/public/images/folder-closed.png +0 -0
- data/public/images/folder.png +0 -0
- data/public/images/node-closed-2.png +0 -0
- data/public/images/node-closed-light.png +0 -0
- data/public/images/node-closed.png +0 -0
- data/public/images/node-opened-2.png +0 -0
- data/public/images/node-opened-light.png +0 -0
- data/public/images/node-opened.png +0 -0
- data/public/img/ajax-loader-dark.gif +0 -0
- data/public/img/ajax-loader-light.gif +0 -0
- data/public/img/ajax-loader.gif +0 -0
- data/public/js/angular-animate.js +4115 -0
- data/public/js/angular-cookies.js +322 -0
- data/public/js/angular-local-storage.js +455 -0
- data/public/js/angular-route.js +1022 -0
- data/public/js/angular-sanitize.js +717 -0
- data/public/js/angular-strap.js +4339 -0
- data/public/js/angular-strap.tpl.js +43 -0
- data/public/js/angular-ui-tree.js +1569 -0
- data/public/js/angular.js +30714 -0
- data/public/js/i18n/angular-locale_pl.js +115 -0
- data/public/js/lodash.custom.min.js +97 -0
- data/public/js/ng-file-upload-shim.min.js +2 -0
- data/public/js/ng-file-upload.min.js +3 -0
- data/views/app.coffee +3 -0
- data/views/engine2.coffee +557 -0
- data/views/engine2actions.coffee +849 -0
- data/views/engine2templates.coffee +0 -0
- data/views/fields/blob.slim +22 -0
- data/views/fields/bs_select.slim +10 -0
- data/views/fields/bsselect_picker.slim +18 -0
- data/views/fields/bsselect_picker_opt.slim +22 -0
- data/views/fields/checkbox.slim +11 -0
- data/views/fields/checkbox_buttons.slim +6 -0
- data/views/fields/checkbox_buttons_opt.slim +8 -0
- data/views/fields/currency.slim +10 -0
- data/views/fields/date.slim +21 -0
- data/views/fields/date_range.slim +44 -0
- data/views/fields/date_time.slim +42 -0
- data/views/fields/datetime.slim +42 -0
- data/views/fields/decimal.slim +11 -0
- data/views/fields/decimal_date.slim +22 -0
- data/views/fields/decimal_time.slim +26 -0
- data/views/fields/email.slim +13 -0
- data/views/fields/file_store.slim +61 -0
- data/views/fields/input_text.slim +14 -0
- data/views/fields/integer.slim +11 -0
- data/views/fields/list_bsselect.slim +18 -0
- data/views/fields/list_bsselect_opt.slim +21 -0
- data/views/fields/list_buttons.slim +3 -0
- data/views/fields/list_buttons_opt.slim +5 -0
- data/views/fields/list_select.slim +11 -0
- data/views/fields/list_select_opt.slim +15 -0
- data/views/fields/password.slim +14 -0
- data/views/fields/radio_checkbox.slim +10 -0
- data/views/fields/scaffold.slim +2 -0
- data/views/fields/scaffold_picker.slim +20 -0
- data/views/fields/select_picker.slim +12 -0
- data/views/fields/select_picker_opt.slim +16 -0
- data/views/fields/text_area.slim +10 -0
- data/views/fields/time.slim +22 -0
- data/views/fields/typeahead_picker.slim +25 -0
- data/views/index.slim +44 -0
- data/views/infra/index.slim +5 -0
- data/views/infra/inspect.slim +81 -0
- data/views/modals/close_m.slim +15 -0
- data/views/modals/confirm_m.slim +19 -0
- data/views/modals/empty_m.slim +12 -0
- data/views/modals/menu_m.slim +13 -0
- data/views/modals/yes_no_m.slim +19 -0
- data/views/panels/menu_m.slim +9 -0
- data/views/scaffold/confirm.slim +3 -0
- data/views/scaffold/fields.slim +10 -0
- data/views/scaffold/form.slim +11 -0
- data/views/scaffold/list.slim +42 -0
- data/views/scaffold/message.slim +3 -0
- data/views/scaffold/search.slim +20 -0
- data/views/scaffold/view.slim +18 -0
- data/views/search_fields/bsmselect_picker.slim +25 -0
- data/views/search_fields/bsselect_picker.slim +24 -0
- data/views/search_fields/checkbox.slim +11 -0
- data/views/search_fields/checkbox2.slim +14 -0
- data/views/search_fields/checkbox_buttons.slim +10 -0
- data/views/search_fields/date_range.slim +46 -0
- data/views/search_fields/decimal_date_range.slim +47 -0
- data/views/search_fields/input_text.slim +18 -0
- data/views/search_fields/integer.slim +18 -0
- data/views/search_fields/integer_range.slim +27 -0
- data/views/search_fields/list_bsmselect.slim +24 -0
- data/views/search_fields/list_bsselect.slim +22 -0
- data/views/search_fields/list_buttons.slim +8 -0
- data/views/search_fields/list_select.slim +17 -0
- data/views/search_fields/scaffold_picker.slim +19 -0
- data/views/search_fields/select_picker.slim +17 -0
- data/views/search_fields/typeahead_picker.slim +25 -0
- metadata +327 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
class StarToManyLinkMeta < Meta
|
|
5
|
+
include MetaModelSupport
|
|
6
|
+
http_method :post
|
|
7
|
+
meta_type :star_to_many_link
|
|
8
|
+
|
|
9
|
+
def invoke handler
|
|
10
|
+
json = handler.post_to_json
|
|
11
|
+
parent = json[:parent_id]
|
|
12
|
+
ids = json[:ids]
|
|
13
|
+
handler.permit parent && ids
|
|
14
|
+
model = assets[:model]
|
|
15
|
+
assoc = assets[:assoc]
|
|
16
|
+
case assoc[:type]
|
|
17
|
+
when :one_to_many
|
|
18
|
+
model.db.transaction do
|
|
19
|
+
self.class.one_to_many_link_db model, assoc, split_keys(parent), ids
|
|
20
|
+
end
|
|
21
|
+
{}
|
|
22
|
+
when :many_to_many
|
|
23
|
+
self.class.many_to_many_link_db model, assoc, split_keys(parent), ids
|
|
24
|
+
{}
|
|
25
|
+
else unsupported_association
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.one_to_many_link_db model, assoc, parent, ids
|
|
30
|
+
pk = Hash[assoc[:keys].zip(parent)]
|
|
31
|
+
ids.each do |id|
|
|
32
|
+
model.where(model.primary_keys_hash(Sequel::split_keys(id))).update(pk)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.many_to_many_link_db model, assoc, parent, ids
|
|
37
|
+
p_pk = Hash[assoc[:left_keys].zip(parent)]
|
|
38
|
+
values = ids.map do |id|
|
|
39
|
+
p_pk.merge Hash[assoc[:right_keys].zip(Sequel::split_keys(id))]
|
|
40
|
+
end
|
|
41
|
+
model.db[assoc[:join_table]].multi_insert values
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class StarToManyUnlinkMetaBase < Meta
|
|
46
|
+
include MetaModelSupport
|
|
47
|
+
http_method :delete
|
|
48
|
+
|
|
49
|
+
def one_to_many_unlink_db handler, ids
|
|
50
|
+
model = assets[:model]
|
|
51
|
+
assoc = assets[:assoc]
|
|
52
|
+
keys = assoc[:keys]
|
|
53
|
+
if keys.all?{|k|model.db_schema[k][:allow_null] == true}
|
|
54
|
+
model.db.transaction do
|
|
55
|
+
self.class.one_to_many_unlink_db model, assoc, ids
|
|
56
|
+
end
|
|
57
|
+
{}
|
|
58
|
+
else
|
|
59
|
+
handler.halt_method_not_allowed LOCS[:"non_nullable"]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.one_to_many_unlink_db model, assoc, ids
|
|
64
|
+
keys = assoc[:keys]
|
|
65
|
+
ids.each do |id|
|
|
66
|
+
model.where(model.primary_keys_hash(Sequel::split_keys(id))).update(Hash[keys.zip([nil])])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def many_to_many_unlink_db parent, ids
|
|
71
|
+
model = assets[:model]
|
|
72
|
+
assoc = assets[:assoc]
|
|
73
|
+
|
|
74
|
+
model.db.transaction do
|
|
75
|
+
self.class.many_to_many_unlink_db model, assoc, Sequel::split_keys(parent), ids
|
|
76
|
+
end
|
|
77
|
+
{}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.many_to_many_unlink_db model, assoc, parent, ids
|
|
81
|
+
p_pk = Hash[assoc[:left_keys].zip(parent)]
|
|
82
|
+
ds = model.db[assoc[:join_table]]
|
|
83
|
+
ids.each do |id|
|
|
84
|
+
ds.where(p_pk, Hash[assoc[:right_keys].zip(Sequel::split_keys(id))]).delete
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class StarToManyUnlinkMeta < StarToManyUnlinkMetaBase
|
|
90
|
+
meta_type :star_to_many_unlink
|
|
91
|
+
|
|
92
|
+
def pre_run
|
|
93
|
+
super
|
|
94
|
+
action.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def invoke handler
|
|
98
|
+
handler.permit id = handler.params[:id]
|
|
99
|
+
assoc = assets[:assoc]
|
|
100
|
+
case assoc[:type]
|
|
101
|
+
when :one_to_many
|
|
102
|
+
one_to_many_unlink_db(handler, [id])
|
|
103
|
+
when :many_to_many
|
|
104
|
+
handler.permit parent = handler.params[:parent_id]
|
|
105
|
+
many_to_many_unlink_db(parent, [id])
|
|
106
|
+
else unsupported_association
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class StarToManyBulkUnlinkMeta < StarToManyUnlinkMetaBase
|
|
112
|
+
meta_type :star_to_many_bulk_unlink
|
|
113
|
+
|
|
114
|
+
def pre_run
|
|
115
|
+
super
|
|
116
|
+
action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_unlink, icon: "minus", show: "action.selected_size() > 0", button_loc: false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def invoke handler
|
|
120
|
+
ids = handler.param_to_json(:ids)
|
|
121
|
+
handler.permit ids.is_a?(Array)
|
|
122
|
+
assoc = assets[:assoc]
|
|
123
|
+
case assoc[:type]
|
|
124
|
+
when :one_to_many
|
|
125
|
+
one_to_many_unlink_db(handler, ids)
|
|
126
|
+
when :many_to_many
|
|
127
|
+
handler.permit parent = handler.params[:parent_id]
|
|
128
|
+
many_to_many_unlink_db(parent, ids)
|
|
129
|
+
else unsupported_association
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
class ListMeta < Meta
|
|
5
|
+
meta_type :list
|
|
6
|
+
include MetaListSupport, MetaQuerySupport
|
|
7
|
+
|
|
8
|
+
(DefaultFilters ||= {}).merge!(
|
|
9
|
+
string: lambda{|query, name, value, type_info, hash|
|
|
10
|
+
case type_info[:type]
|
|
11
|
+
when :many_to_one
|
|
12
|
+
query.where(name => value)
|
|
13
|
+
else
|
|
14
|
+
query.where(name.like("%#{value}%"))
|
|
15
|
+
end
|
|
16
|
+
},
|
|
17
|
+
date: lambda{|query, name, value, type_info, hash|
|
|
18
|
+
if value.is_a? Hash
|
|
19
|
+
from, to = value[:from], value[:to]
|
|
20
|
+
if from && to
|
|
21
|
+
query.where(name => from .. to)
|
|
22
|
+
elsif from
|
|
23
|
+
query.where(name >= Sequel.string_to_date(from))
|
|
24
|
+
elsif to
|
|
25
|
+
query.where(name <= Sequel.string_to_date(to))
|
|
26
|
+
else
|
|
27
|
+
query # ?
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
query.where(name => Sequel.string_to_date(value))
|
|
31
|
+
end
|
|
32
|
+
},
|
|
33
|
+
integer: lambda{|query, name, value, type_info, hash|
|
|
34
|
+
if value.is_a? Hash
|
|
35
|
+
from, to = value[:from], value[:to]
|
|
36
|
+
if from && to
|
|
37
|
+
query.where(name => from .. to)
|
|
38
|
+
else
|
|
39
|
+
query.where(from ? name >= from.to_i : name <= to.to_i)
|
|
40
|
+
end
|
|
41
|
+
elsif value.is_a? Integer
|
|
42
|
+
query.where(name => value)
|
|
43
|
+
elsif value.is_a? Array
|
|
44
|
+
if !value.empty?
|
|
45
|
+
case type_info[:type]
|
|
46
|
+
when :many_to_one
|
|
47
|
+
keys = type_info[:keys]
|
|
48
|
+
if keys.length == 1
|
|
49
|
+
query.where(name => value)
|
|
50
|
+
else
|
|
51
|
+
query.where(keys.map{|k| hash[k]}.transpose.map{|vals| Hash[keys.zip(vals)]}.inject{|q, c| q | c
|
|
52
|
+
})
|
|
53
|
+
end
|
|
54
|
+
when :list_select
|
|
55
|
+
query.where(name => value) # decode in sql query ?
|
|
56
|
+
when :integer
|
|
57
|
+
query
|
|
58
|
+
else
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
nil
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def post_run
|
|
71
|
+
query select(*assets[:model].columns.reject{|col| assets[:model].type_info[col][:length].to_i > 20}.take(10)) unless @query
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def invoke handler
|
|
76
|
+
params = handler.params
|
|
77
|
+
model = assets[:model]
|
|
78
|
+
query = list_context(get_query, handler)
|
|
79
|
+
|
|
80
|
+
if search = params[:search]
|
|
81
|
+
query = list_search(query, handler, search)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
count = query.count if lookup(:config, :use_count)
|
|
85
|
+
|
|
86
|
+
if order_str = params[:order]
|
|
87
|
+
order = order_str.to_sym
|
|
88
|
+
handler.permit lookup(:info, order, :sort)
|
|
89
|
+
|
|
90
|
+
if order_blk = (@orders && @orders[order]) || (dynamic? && (static.orders && static.orders[order]))
|
|
91
|
+
query = order_blk.(query, handler)
|
|
92
|
+
else
|
|
93
|
+
order = order.qualify(model.table_name) if model.type_info[order]
|
|
94
|
+
query = query.order(order)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
query = query.reverse if params[:asc] == "true"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
per_page = lookup(:config, :per_page)
|
|
101
|
+
page = params[:page].to_i
|
|
102
|
+
handler.permit page >= 0 && page < 1000
|
|
103
|
+
|
|
104
|
+
query = query.limit(per_page, page)
|
|
105
|
+
|
|
106
|
+
res = {entries: query.all}
|
|
107
|
+
res[:count] = count if count
|
|
108
|
+
res
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def list_search query, handler, search
|
|
112
|
+
hash = JSON.parse(search, symbolize_names: true) rescue handler.halt_forbidden
|
|
113
|
+
model = assets[:model]
|
|
114
|
+
sfields = lookup(:search_fields)
|
|
115
|
+
handler.permit sfields
|
|
116
|
+
hash.each_pair do |name, value|
|
|
117
|
+
handler.permit sfields.include?(name)
|
|
118
|
+
|
|
119
|
+
type_info = get_type_info(name)
|
|
120
|
+
query = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
|
|
121
|
+
filter.(query, hash, handler)
|
|
122
|
+
elsif filter = DefaultFilters[type_info[:otype]]
|
|
123
|
+
name = model.type_info[name] ? name.qualify(model.table_name) : Sequel.expr(name)
|
|
124
|
+
filter.(query, name, value, type_info, hash)
|
|
125
|
+
else
|
|
126
|
+
raise E2Error.new("Filter not found for field #{name} in model #{model}") unless filter
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
handler.permit query
|
|
130
|
+
end
|
|
131
|
+
query
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def list_context query, handler
|
|
135
|
+
query
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
#
|
|
140
|
+
# Many to One
|
|
141
|
+
#
|
|
142
|
+
class ManyToOneListMeta < ListMeta
|
|
143
|
+
meta_type :many_to_one_list
|
|
144
|
+
|
|
145
|
+
def pre_run
|
|
146
|
+
super
|
|
147
|
+
config.merge!(selectable: false)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
#
|
|
152
|
+
# * to Many
|
|
153
|
+
#
|
|
154
|
+
class StarToManyListMeta < ListMeta
|
|
155
|
+
meta_type :star_to_many_list
|
|
156
|
+
def pre_run
|
|
157
|
+
super
|
|
158
|
+
panel_title "#{glyphicon('list')} #{LOCS[assets[:assoc][:name]]}"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# def decode_panel_title handler
|
|
162
|
+
# if handler.initial?
|
|
163
|
+
# # Hash[assets[:model].primary_keys.zip(split_keys(id))]]
|
|
164
|
+
# p action.parent.decode_entry.*.invoke_decode([[handler.params[:parent_id]]])
|
|
165
|
+
# panel_title "ADFASDF"
|
|
166
|
+
# end
|
|
167
|
+
# end
|
|
168
|
+
|
|
169
|
+
# def post_run
|
|
170
|
+
# super
|
|
171
|
+
# unless @request_meta_proc
|
|
172
|
+
# request{|h| decode_panel_title h}
|
|
173
|
+
# end
|
|
174
|
+
# end
|
|
175
|
+
|
|
176
|
+
def list_context query, handler
|
|
177
|
+
handler.permit parent = handler.params[:parent_id]
|
|
178
|
+
model = assets[:model]
|
|
179
|
+
assoc = assets[:assoc]
|
|
180
|
+
case assoc[:type]
|
|
181
|
+
when :one_to_many
|
|
182
|
+
keys = assoc[:keys]
|
|
183
|
+
condition = parent.empty? ? false : Hash[keys.map{|k| k.qualify(model.table_name)}.zip(split_keys(parent))]
|
|
184
|
+
if handler.params[:negate]
|
|
185
|
+
query = query.exclude(condition)
|
|
186
|
+
query = query.or(Hash[keys.zip([nil])]) if keys.all?{|k|model.db_schema[k][:allow_null] == true} # type_info[:required] ?
|
|
187
|
+
query
|
|
188
|
+
else
|
|
189
|
+
query.where(condition)
|
|
190
|
+
end
|
|
191
|
+
when :many_to_many
|
|
192
|
+
q_pk = model.primary_keys_qualified
|
|
193
|
+
j_table = assoc[:join_table]
|
|
194
|
+
l_keys = assoc[:left_keys].map{|k| k.qualify(j_table)}
|
|
195
|
+
r_keys = assoc[:right_keys].map{|k| k.qualify(j_table)}
|
|
196
|
+
r_keys_vals = Hash[r_keys.zip(q_pk)]
|
|
197
|
+
l_keys_vals = parent.empty? ? false : Hash[l_keys.zip(split_keys(parent))]
|
|
198
|
+
|
|
199
|
+
if handler.params[:negate]
|
|
200
|
+
query.exclude(model.db[j_table].select(nil).where(r_keys_vals, l_keys_vals).exists)
|
|
201
|
+
else
|
|
202
|
+
# query.qualify.join(j_table, [r_keys_vals, l_keys_vals])
|
|
203
|
+
query.qualify.left_join(j_table, r_keys_vals).filter(l_keys_vals)
|
|
204
|
+
end
|
|
205
|
+
else unsupported_association
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class StarToManyLinkListMeta < StarToManyListMeta
|
|
211
|
+
meta_type :star_to_many_link_list
|
|
212
|
+
def pre_run
|
|
213
|
+
super
|
|
214
|
+
config.merge!(selectable: false)
|
|
215
|
+
panel_title LOCS[:link_title]
|
|
216
|
+
menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
|
|
217
|
+
action.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# *_to_many_field
|
|
222
|
+
class StarToManyFieldMeta < StarToManyListMeta
|
|
223
|
+
meta_type :star_to_many_field
|
|
224
|
+
|
|
225
|
+
def pre_run
|
|
226
|
+
super
|
|
227
|
+
modal_action false
|
|
228
|
+
panel_panel_template false
|
|
229
|
+
# panel_template nil
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def list_context query, handler
|
|
233
|
+
unlinked = handler.param_to_json(:unlinked)
|
|
234
|
+
linked = handler.param_to_json(:linked)
|
|
235
|
+
query = super(query, handler)
|
|
236
|
+
model = assets[:model]
|
|
237
|
+
pks = model.primary_keys_qualified
|
|
238
|
+
|
|
239
|
+
if handler.params[:negate]
|
|
240
|
+
query = unlinked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}
|
|
241
|
+
# query = query.or *unlinked.map{|unl| Hash[model.primary_keys.zip(split_keys(unl))]}.inject{|q, c| q | c}
|
|
242
|
+
query = query.where *linked.map{|ln| pks.zip(split_keys(ln)).sql_negate}
|
|
243
|
+
|
|
244
|
+
else
|
|
245
|
+
query = query.where *unlinked.map{|unl| pks.zip(split_keys(unl)).sql_negate}
|
|
246
|
+
# query = query.or *linked.map{|ln| model.primary_keys.zip(split_keys(ln))}
|
|
247
|
+
# query = query.or *linked.map{|ln| Hash[model.primary_keys.zip(split_keys(ln))]}.inject{|q, c| q | c}
|
|
248
|
+
case assets[:assoc][:type]
|
|
249
|
+
when :one_to_many
|
|
250
|
+
query = linked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}
|
|
251
|
+
when :many_to_many
|
|
252
|
+
query = linked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}.distinct
|
|
253
|
+
else unsupported_association
|
|
254
|
+
end unless linked.empty?
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
query
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
class StarToManyFieldUnlinkMeta < Meta
|
|
262
|
+
meta_type :star_to_many_field_unlink
|
|
263
|
+
|
|
264
|
+
def pre_run
|
|
265
|
+
super
|
|
266
|
+
action.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
class StarToManyFieldLinkListMeta < StarToManyFieldMeta
|
|
271
|
+
meta_type :star_to_many_field_link_list
|
|
272
|
+
|
|
273
|
+
def pre_run
|
|
274
|
+
super
|
|
275
|
+
config.merge!(selectable: false)
|
|
276
|
+
modal_action true
|
|
277
|
+
panel_panel_template 'scaffold/list'
|
|
278
|
+
panel_title LOCS[:link_title]
|
|
279
|
+
menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
|
|
280
|
+
action.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
|
|
5
|
+
class SaveMeta < Meta
|
|
6
|
+
include MetaApproveSupport
|
|
7
|
+
http_method :post
|
|
8
|
+
|
|
9
|
+
def validate_and_approve handler, record, json
|
|
10
|
+
record.skip_save_refresh = true
|
|
11
|
+
record.raise_on_save_failure = false
|
|
12
|
+
model = assets[:model]
|
|
13
|
+
assoc = assets[:assoc]
|
|
14
|
+
mtm_insert = record.new? && assoc && assoc[:type] == :many_to_many
|
|
15
|
+
|
|
16
|
+
save = lambda do|c|
|
|
17
|
+
if super(handler, record, json)
|
|
18
|
+
result = record.save(transaction: false, validate: false)
|
|
19
|
+
if result && mtm_insert
|
|
20
|
+
handler.permit parent_id = json[:parent_id]
|
|
21
|
+
model.db[assoc[:join_table]].insert(assoc[:left_keys] + assoc[:right_keys], split_keys(parent_id) + record.primary_key_values)
|
|
22
|
+
end
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
(model.validation_in_transaction || mtm_insert) ? model.db.transaction(&save) : save.(nil)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class InsertMeta < SaveMeta
|
|
31
|
+
meta_type :save
|
|
32
|
+
def allocate_record handler, json
|
|
33
|
+
record = super(handler, json)
|
|
34
|
+
record.instance_variable_set(:"@new", true)
|
|
35
|
+
model = assets[:model]
|
|
36
|
+
model.primary_keys.each{|k|record.values.delete k} unless model.natural_key
|
|
37
|
+
handler.permit !record.has_primary_key? unless model.natural_key
|
|
38
|
+
record
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class UpdateMeta < SaveMeta
|
|
43
|
+
meta_type :save
|
|
44
|
+
def allocate_record handler, json
|
|
45
|
+
record = super(handler, json)
|
|
46
|
+
model = assets[:model]
|
|
47
|
+
handler.permit record.has_primary_key? unless model.natural_key
|
|
48
|
+
record
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module TimeStampMeta
|
|
53
|
+
def before_approve handler, record
|
|
54
|
+
super
|
|
55
|
+
puts "before approve"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def after_approve handler, record
|
|
59
|
+
super
|
|
60
|
+
puts "after approve"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|