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,110 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
class DecodeMeta < Meta
|
|
5
|
+
include MetaAPISupport, MetaModelSupport, MetaQuerySupport
|
|
6
|
+
|
|
7
|
+
def decode *fields, &blk
|
|
8
|
+
query select(*fields), &blk
|
|
9
|
+
@meta[:decode_fields] = fields
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def separator sep
|
|
13
|
+
@meta[:separator] = sep
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def show_max_selected max
|
|
17
|
+
@meta[:show_max_selected] = max
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def post_process
|
|
21
|
+
if fields = @meta[:fields]
|
|
22
|
+
fields = fields - static.get[:fields] if dynamic?
|
|
23
|
+
# no decorate here
|
|
24
|
+
fields.each do |name|
|
|
25
|
+
type_info = assets[:model].type_info[name] # foreign keys ?
|
|
26
|
+
proc = ListRendererPostProcessors[type_info[:type]] # like... checkboxes, list_selects
|
|
27
|
+
proc.(self, name, type_info) if proc
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
# no super
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def pre_run
|
|
34
|
+
super
|
|
35
|
+
if assoc = assets[:assoc]
|
|
36
|
+
decode = assoc[:model].type_info[assoc[:keys].first][:decode]
|
|
37
|
+
if decode[:search][:multiple]
|
|
38
|
+
show_max_selected 3
|
|
39
|
+
@meta[:decode_selected] = LOCS[:decode_selected]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def post_run
|
|
45
|
+
query select(*assets[:model].primary_keys) unless @query
|
|
46
|
+
@meta[:separator] = '/' unless @meta[:separator]
|
|
47
|
+
super
|
|
48
|
+
@meta[:primary_fields] = assets[:model].primary_keys
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class DecodeListMeta < DecodeMeta
|
|
54
|
+
meta_type :decode_list
|
|
55
|
+
|
|
56
|
+
def invoke handler
|
|
57
|
+
{entries: get_query.limit(200).all}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class TypeAheadMeta < DecodeMeta
|
|
62
|
+
meta_type :typeahead
|
|
63
|
+
|
|
64
|
+
def pre_run
|
|
65
|
+
super
|
|
66
|
+
limit 10
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def limit lmt
|
|
70
|
+
@meta[:limit] = lmt
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def invoke handler
|
|
74
|
+
if query = handler.params[:query]
|
|
75
|
+
condition = (@meta[:decode_fields] || @meta[:fields]).map{|f|f.like("%#{query}%")}.inject{|q, f| q | f}
|
|
76
|
+
{entries: get_query.where(condition).limit(@meta[:limit]).all}
|
|
77
|
+
else
|
|
78
|
+
handler.permit id = handler.params[:id]
|
|
79
|
+
record = get_query[Hash[assets[:model].primary_keys.zip(split_keys(id))]]
|
|
80
|
+
# handler.halt_not_found(LOCS[:no_entry]) unless record
|
|
81
|
+
{entry: record}
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class DecodeEntryMeta < DecodeMeta
|
|
87
|
+
meta_type :decode_entry
|
|
88
|
+
|
|
89
|
+
def invoke handler
|
|
90
|
+
{entries: invoke_decode(handler, handler.param_to_json(:ids))}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def invoke_decode handler, ids
|
|
94
|
+
records = get_query.where(ids.map{|keys| Hash[assets[:model].primary_keys.zip(keys)]}.inject{|q, c| q | c}).all
|
|
95
|
+
# handler.halt_not_found(LOCS[:no_entry]) if records.empty?
|
|
96
|
+
records
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def post_run
|
|
100
|
+
super
|
|
101
|
+
if assoc = assets[:assoc]
|
|
102
|
+
decode = assoc[:model].type_info[assoc[:keys].first][:decode]
|
|
103
|
+
|
|
104
|
+
if decode[:search][:multiple] && action.parent.parent.*.is_a?(ListMeta)
|
|
105
|
+
action.list.*.menu(:panel_menu).option_at 0, :choose, icon: :ok # , disabled: "action.selected_size() == 0"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
class DeleteMetaBase < Meta
|
|
5
|
+
include MetaModelSupport
|
|
6
|
+
|
|
7
|
+
def invoke_delete_db handler, ids
|
|
8
|
+
begin
|
|
9
|
+
model = assets[:model]
|
|
10
|
+
model.db.transaction do
|
|
11
|
+
ids.each do |id|
|
|
12
|
+
keys = split_keys(id)
|
|
13
|
+
restrict = model.association_reflections.select do |name, rel|
|
|
14
|
+
case rel[:type]
|
|
15
|
+
when :one_to_many
|
|
16
|
+
!model.db[name].where(Hash[rel[:keys].zip(keys)]).empty?
|
|
17
|
+
when :many_to_many
|
|
18
|
+
!model.db[rel[:join_table]].where(Hash[rel[:left_keys].zip(keys)]).empty?
|
|
19
|
+
when :many_to_one
|
|
20
|
+
when :one_to_one
|
|
21
|
+
else
|
|
22
|
+
unsupported_association rel[:type]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
raise Sequel::DestroyFailed.new("Blokujące relacje: #{restrict.map{|name, rel| name}.join(', ')}" ) unless restrict.empty?
|
|
26
|
+
|
|
27
|
+
rec = model.call(Hash[model.primary_keys.zip(keys)])
|
|
28
|
+
rec.destroy(transaction: false)
|
|
29
|
+
# model.where(model.primary_keys_hash(keys)).delete # model.dataset[model.primary_key => id].delete
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
{}
|
|
33
|
+
rescue Sequel::NoExistingObject
|
|
34
|
+
handler.halt_not_found LOCS[:no_entry]
|
|
35
|
+
rescue Sequel::DestroyFailed => failure
|
|
36
|
+
handler.halt_forbidden failure.error.to_s
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class DeleteMeta < DeleteMetaBase
|
|
43
|
+
http_method :delete
|
|
44
|
+
meta_type :delete
|
|
45
|
+
|
|
46
|
+
def pre_run
|
|
47
|
+
super
|
|
48
|
+
action.parent.parent.*.menu(:item_menu).option :confirm_delete, icon: "trash", show: "action.selected_size() == 0", button_loc: false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def invoke handler
|
|
52
|
+
handler.permit id = handler.params[:id]
|
|
53
|
+
invoke_delete_db(handler, [id])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class BulkDeleteMeta < DeleteMetaBase
|
|
58
|
+
http_method :delete
|
|
59
|
+
meta_type :bulk_delete
|
|
60
|
+
|
|
61
|
+
def pre_run
|
|
62
|
+
super
|
|
63
|
+
action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_delete, icon: "trash", show: "action.selected_size() > 0"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def invoke handler
|
|
67
|
+
ids = handler.param_to_json(:ids)
|
|
68
|
+
handler.permit ids.is_a?(Array)
|
|
69
|
+
invoke_delete_db(handler, ids)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
class FormMeta < Meta
|
|
5
|
+
include MetaAPISupport, MetaModelSupport, MetaQuerySupport, MetaTabSupport, MetaPanelSupport, MetaMenuSupport, MetaAngularSupport, MetaOnChangeSupport
|
|
6
|
+
|
|
7
|
+
def field_template template
|
|
8
|
+
panel[:field_template] = template
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def pre_run
|
|
12
|
+
super
|
|
13
|
+
panel_template 'scaffold/form'
|
|
14
|
+
field_template 'scaffold/fields'
|
|
15
|
+
panel_class 'modal-large'
|
|
16
|
+
|
|
17
|
+
menu :panel_menu do
|
|
18
|
+
option :approve, icon: "ok", disabled: 'action.action_pending' # text: true,
|
|
19
|
+
option :cancel, icon: "remove" # text: true,
|
|
20
|
+
end
|
|
21
|
+
# modal_action false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def record handler, record
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def post_process
|
|
28
|
+
if fields = @meta[:fields]
|
|
29
|
+
fields = fields - static.get[:fields] if dynamic?
|
|
30
|
+
|
|
31
|
+
decorate(fields)
|
|
32
|
+
|
|
33
|
+
fields.each do |name|
|
|
34
|
+
# type_info = model.type_info.fetch(name)
|
|
35
|
+
type_info = get_type_info(name)
|
|
36
|
+
|
|
37
|
+
info[name][:render] ||= begin
|
|
38
|
+
renderer = DefaultFormRenderers[type_info[:type]] # .merge(default: true)
|
|
39
|
+
raise E2Error.new("No form renderer found for field '#{type_info[:name]}' of type '#{type_info[:type]}'") unless renderer
|
|
40
|
+
renderer.(self, type_info)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
proc = FormRendererPostProcessors[type_info[:type]]
|
|
44
|
+
proc.(self, name, type_info) if proc
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
assoc = assets[:assoc]
|
|
48
|
+
if assoc && assoc[:type] == :one_to_many
|
|
49
|
+
# fields.select{|f| assoc[:keys].include? f}.each do |key|
|
|
50
|
+
# # hide_fields(key) if self[:info, key, :hidden] == nil
|
|
51
|
+
# info! key, disabled: true
|
|
52
|
+
# end
|
|
53
|
+
assoc[:keys].each do |key|
|
|
54
|
+
info! key, disabled: true if fields.include? key
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def post_run
|
|
63
|
+
super
|
|
64
|
+
@meta[:primary_fields] = assets[:model].primary_keys
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def template
|
|
68
|
+
Templates
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def hr_after field, message = '-'
|
|
72
|
+
info! field, hr: message
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class CreateMeta < FormMeta
|
|
77
|
+
meta_type :create
|
|
78
|
+
|
|
79
|
+
def pre_run
|
|
80
|
+
super
|
|
81
|
+
panel_title LOCS[:create_title]
|
|
82
|
+
action.parent.*.menu(:menu).option_at 0, action.name, icon: "plus-sign", button_loc: false
|
|
83
|
+
|
|
84
|
+
hide_pk unless assets[:model].natural_key
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def record handler, record
|
|
88
|
+
create_record(handler, record)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def create_record handler, record
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def invoke handler
|
|
95
|
+
record = {}
|
|
96
|
+
if assoc = assets[:assoc]
|
|
97
|
+
case assoc[:type]
|
|
98
|
+
when :one_to_many
|
|
99
|
+
handler.permit parent = handler.params[:parent_id]
|
|
100
|
+
assoc[:keys].zip(split_keys(parent)).each{|key, val| record[key] = val}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
static.record(handler, record)
|
|
104
|
+
{record: record, new: true}
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class ModifyMeta < FormMeta
|
|
109
|
+
meta_type :modify
|
|
110
|
+
|
|
111
|
+
def pre_run
|
|
112
|
+
super
|
|
113
|
+
panel_title LOCS[:modify_title]
|
|
114
|
+
action.parent.*.menu(:item_menu).option action.name, icon: "pencil", button_loc: false
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def record handler, record
|
|
118
|
+
modify_record(handler, record)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def modify_record handler, record
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def invoke handler
|
|
125
|
+
handler.permit id = handler.params[:id]
|
|
126
|
+
record = get_query[assets[:model].primary_keys_hash_qualified(split_keys(id))]
|
|
127
|
+
|
|
128
|
+
if record
|
|
129
|
+
static.record(handler, record)
|
|
130
|
+
{record: record}
|
|
131
|
+
else
|
|
132
|
+
handler.halt_not_found LOCS[:no_entry]
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def post_run
|
|
137
|
+
super
|
|
138
|
+
assets[:model].primary_keys.each do |key| # pre_run ?
|
|
139
|
+
info! key, disabled: true
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Engine2
|
|
4
|
+
SCHEMES::define_scheme :infra! do |user_info_model = UserInfo|
|
|
5
|
+
define_action :infra! do
|
|
6
|
+
self.* do
|
|
7
|
+
extend MetaPanelSupport, MetaMenuSupport
|
|
8
|
+
panel_panel_template false
|
|
9
|
+
panel_template 'infra/index'
|
|
10
|
+
menu :menu do
|
|
11
|
+
properties group_class: "btn-group-sm"
|
|
12
|
+
option :inspect_modal, icon: :wrench, button_loc: false # , show: "action.logged_on"
|
|
13
|
+
|
|
14
|
+
option :logout_form, icon: :"log-out" # , show: "action.logged_on"
|
|
15
|
+
option :login_form, icon: :"log-in" # , show: "!action.logged_on"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
@meta_type = :infra
|
|
19
|
+
|
|
20
|
+
def invoke handler
|
|
21
|
+
user = handler.user
|
|
22
|
+
{user: user ? user.to_hash : nil}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
define_action :login_form, LoginFormMeta, model: user_info_model do
|
|
27
|
+
access!{|h|!h.logged_in?}
|
|
28
|
+
define_action :login, LoginMeta
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
define_action :logout_form, LogoutFormMeta do
|
|
32
|
+
access! &:logged_in?
|
|
33
|
+
define_action :logout, LogoutMeta
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
define_action :inspect_modal do
|
|
37
|
+
access! &:logged_in?
|
|
38
|
+
# access!{|h|h.user[:name] == 'admin'}
|
|
39
|
+
self.* do
|
|
40
|
+
extend MetaPanelSupport, MetaMenuSupport
|
|
41
|
+
modal_action
|
|
42
|
+
panel_template 'infra/inspect'
|
|
43
|
+
panel_title "Inspect"
|
|
44
|
+
panel_class "modal-huge"
|
|
45
|
+
menu(:panel_menu).option :cancel, icon: "remove"
|
|
46
|
+
|
|
47
|
+
# def invoke handler;{};end
|
|
48
|
+
end
|
|
49
|
+
define_action :inspect do
|
|
50
|
+
self.* do
|
|
51
|
+
@meta_type = :inspect
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
define_action :models do
|
|
55
|
+
def (self.*).invoke handler
|
|
56
|
+
{models: Sequel::DATABASES.map{|db| {name: db.uri, models: db.models.keys} }}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
define_action :model_info do
|
|
61
|
+
def (self.*).invoke handler
|
|
62
|
+
db_name = handler.params[:db]
|
|
63
|
+
handler.permit db = Sequel::DATABASES.find{|d|d.uri == db_name || (d.uri && d.uri.start_with?(db_name))}
|
|
64
|
+
handler.permit model = db.models[handler.params[:model].to_sym]
|
|
65
|
+
{
|
|
66
|
+
model: {
|
|
67
|
+
info: {
|
|
68
|
+
name: model.to_s,
|
|
69
|
+
table: model.table_name
|
|
70
|
+
},
|
|
71
|
+
assoc: model.association_reflections,
|
|
72
|
+
schema: model.db_schema,
|
|
73
|
+
type_info: model.type_info
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
SCHEMES::define_scheme :menu! do
|
|
84
|
+
define_action :menu!, MenuMeta do
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class FileStoreMeta < Meta
|
|
89
|
+
meta_type :file_store
|
|
90
|
+
|
|
91
|
+
attr_accessor :model, :field
|
|
92
|
+
|
|
93
|
+
def invoke handler
|
|
94
|
+
handler.permit owner = handler.params[:owner]
|
|
95
|
+
{files: E2Files.db[:files].select(:id, :name, :mime, :uploaded).where(owner: owner, model: model.name.to_s, field: field.to_s).all}
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
module BlobSupportMeta
|
|
101
|
+
def serve_blob handler, entry, inf
|
|
102
|
+
handler.permit entry
|
|
103
|
+
handler.attachment entry[inf[:name_field]]
|
|
104
|
+
handler.content_type (entry[inf[:mime_field]].to_s.empty? ? "application/octet-stream" : entry[inf[:mime_field]])
|
|
105
|
+
entry[inf[:bytes_field]].getBinaryStream().to_io.read
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class DownloadFileStoreMeta < Meta
|
|
110
|
+
meta_type :download
|
|
111
|
+
|
|
112
|
+
def invoke handler
|
|
113
|
+
handler.permit id = handler.params[:id]
|
|
114
|
+
entry = E2Files.db[:files].select(:name, :mime)[id: id]
|
|
115
|
+
handler.permit entry
|
|
116
|
+
handler.attachment entry[:name]
|
|
117
|
+
handler.content_type (entry[:mime].to_s.empty? ? "application/octet-stream" : entry[:mime])
|
|
118
|
+
info = action.parent.*.model.type_info[action.parent.*.field]
|
|
119
|
+
open("#{info[:store][:files]}/#{entry[:name]}_#{id}", 'rb'){|f|f.read}
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
class UploadFileStoreMeta < Meta
|
|
124
|
+
http_method :post
|
|
125
|
+
meta_type :upload
|
|
126
|
+
|
|
127
|
+
def invoke handler
|
|
128
|
+
file = handler.params[:file]
|
|
129
|
+
temp = file[:tempfile]
|
|
130
|
+
temp.close
|
|
131
|
+
rackname = File.basename(temp.path)
|
|
132
|
+
info = action.parent.*.model.type_info[action.parent.*.field]
|
|
133
|
+
File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
|
|
134
|
+
{rackname: rackname}
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class BlobStoreMeta < Meta
|
|
139
|
+
meta_type :blob_store
|
|
140
|
+
|
|
141
|
+
attr_accessor :model, :field
|
|
142
|
+
|
|
143
|
+
def invoke handler
|
|
144
|
+
handler.permit id = handler.params[:owner]
|
|
145
|
+
inf = model.type_info[field]
|
|
146
|
+
result = model.naked.select(inf[:name_field], Sequel.char_length(inf[:bytes_field]).as(:length)).where(model.primary_keys_hash(split_keys(id))).first
|
|
147
|
+
handler.permit result
|
|
148
|
+
{file_name: result[inf[:name_field]], blob_length: result[:length]}
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
class DownloadBlobStoreMeta < Meta
|
|
153
|
+
include BlobSupportMeta
|
|
154
|
+
meta_type :download_blob
|
|
155
|
+
|
|
156
|
+
def invoke handler
|
|
157
|
+
model = action.parent.*.model
|
|
158
|
+
inf = model.type_info[action.parent.*.field]
|
|
159
|
+
handler.permit id = handler.params[:id]
|
|
160
|
+
|
|
161
|
+
entry = model.naked.select(inf[:bytes_field], inf[:name_field], inf[:mime_field]).where(model.primary_keys_hash(split_keys(id))).first
|
|
162
|
+
serve_blob(handler, entry, inf)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
class UploadBlobStoreMeta < Meta
|
|
167
|
+
http_method :post
|
|
168
|
+
meta_type :upload_blob
|
|
169
|
+
|
|
170
|
+
def invoke handler
|
|
171
|
+
file = handler.params[:file]
|
|
172
|
+
temp = file[:tempfile]
|
|
173
|
+
temp.close
|
|
174
|
+
rackname = File.basename(temp.path)
|
|
175
|
+
info = action.parent.*.model.type_info[action.parent.*.field]
|
|
176
|
+
File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
|
|
177
|
+
{rackname: rackname}
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
class ForeignBlobStoreMeta < Meta
|
|
182
|
+
meta_type :blob_store
|
|
183
|
+
|
|
184
|
+
attr_accessor :model, :field
|
|
185
|
+
|
|
186
|
+
def invoke handler
|
|
187
|
+
handler.permit id = handler.params[:owner]
|
|
188
|
+
|
|
189
|
+
inf = model.type_info[field]
|
|
190
|
+
assoc = model.association_reflections[inf[:assoc_name]]
|
|
191
|
+
blob_model = Object.const_get(assoc[:class_name])
|
|
192
|
+
|
|
193
|
+
rec = model.naked.select(assoc[:key]).where(model.primary_keys_hash(split_keys(id))).first
|
|
194
|
+
handler.permit rec
|
|
195
|
+
result = blob_model.naked.select(inf[:name_field], Sequel.char_length(inf[:bytes_field]).as(:length)).where(blob_model.primary_key => rec[assoc[:key]]).first
|
|
196
|
+
|
|
197
|
+
# handler.permit result
|
|
198
|
+
{file_name: result ? result[inf[:name_field]] : :empty, blob_length: result ? result[:length] : 0}
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
class DownloadForeignBlobStoreMeta < Meta
|
|
203
|
+
include BlobSupportMeta
|
|
204
|
+
meta_type :download_blob
|
|
205
|
+
|
|
206
|
+
def invoke handler
|
|
207
|
+
model = action.parent.*.model
|
|
208
|
+
inf = model.type_info[action.parent.*.field]
|
|
209
|
+
assoc = model.association_reflections[inf[:assoc_name]]
|
|
210
|
+
blob_model = Object.const_get(assoc[:class_name])
|
|
211
|
+
handler.permit id = handler.params[:id]
|
|
212
|
+
rec = model.naked.select(assoc[:key]).where(model.primary_keys_hash(split_keys(id))).first
|
|
213
|
+
handler.permit rec
|
|
214
|
+
|
|
215
|
+
entry = blob_model.naked.select(inf[:bytes_field], inf[:name_field], inf[:mime_field]).where(blob_model.primary_key => rec[assoc[:key]]).first
|
|
216
|
+
serve_blob(handler, entry, inf)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# class UploadForeignBlobStoreMeta < Meta
|
|
221
|
+
# http_method :post
|
|
222
|
+
# meta_type :upload_blob
|
|
223
|
+
|
|
224
|
+
# def invoke handler
|
|
225
|
+
# file = handler.params[:file]
|
|
226
|
+
# temp = file[:tempfile]
|
|
227
|
+
# temp.close
|
|
228
|
+
# rackname = File.basename(temp.path)
|
|
229
|
+
# File.rename(temp.path, "#{UPLOAD_DIR}/#{rackname}")
|
|
230
|
+
# {rackname: rackname}
|
|
231
|
+
# end
|
|
232
|
+
# end
|
|
233
|
+
|
|
234
|
+
class LoginFormMeta < FormMeta
|
|
235
|
+
meta_type :login_form
|
|
236
|
+
|
|
237
|
+
def pre_run
|
|
238
|
+
super
|
|
239
|
+
panel_class 'modal-default'
|
|
240
|
+
panel_title LOCS[:login_title]
|
|
241
|
+
info! :name, loc: LOCS[:user_name]
|
|
242
|
+
menu(:panel_menu).modify_option :approve, name: :login, icon: :"log-in"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def invoke handler
|
|
246
|
+
{record: {}, new: true}
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
class LoginMeta < Meta
|
|
251
|
+
include MetaApproveSupport
|
|
252
|
+
http_method :post
|
|
253
|
+
meta_type :login
|
|
254
|
+
|
|
255
|
+
def after_approve handler, record
|
|
256
|
+
handler.session[:user] = record
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def record handler, record
|
|
260
|
+
{errors: nil, user: handler.user.to_hash}
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
class LogoutFormMeta < Meta
|
|
265
|
+
include MetaPanelSupport, MetaMenuSupport
|
|
266
|
+
meta_type :logout_form
|
|
267
|
+
def pre_run
|
|
268
|
+
super
|
|
269
|
+
panel_template 'scaffold/message'
|
|
270
|
+
panel_title LOCS[:logout_title]
|
|
271
|
+
panel_class 'modal-default'
|
|
272
|
+
menu :panel_menu do
|
|
273
|
+
option :logout, icon: "ok", loc: LOCS[:ok]
|
|
274
|
+
option :cancel, icon: "remove"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def invoke handler
|
|
279
|
+
{message: LOCS[:logout_message]}
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
class LogoutMeta < Meta
|
|
284
|
+
meta_type :logout
|
|
285
|
+
|
|
286
|
+
def invoke handler
|
|
287
|
+
handler.session.clear
|
|
288
|
+
# handler.session[:logged_in] = false
|
|
289
|
+
{}
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|