marty 2.3.15 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/app/components/marty/api_auth_view.rb +27 -4
- data/app/components/marty/api_config_view.rb +27 -4
- data/app/components/marty/extras/layout.rb +4 -7
- data/app/components/marty/form.rb +8 -0
- data/app/components/marty/grid.rb +45 -19
- data/app/components/marty/main_auth_app.rb +12 -11
- data/app/controllers/marty/rpc_controller.rb +63 -150
- data/app/models/marty/api_auth.rb +86 -14
- data/app/models/marty/api_config.rb +11 -6
- data/app/models/marty/delorean_rule.rb +3 -2
- data/config/routes.rb +1 -1
- data/db/migrate/501_add_api_class_to_marty_api_config.rb +6 -0
- data/db/migrate/502_add_parameters_to_marty_api_auth.rb +5 -0
- data/lib/marty/util.rb +0 -15
- data/lib/marty/version.rb +1 -1
- data/other/marty/api/base.rb +207 -0
- data/other/marty/diagnostic/aws/ec2_instance.rb +12 -87
- data/other/marty/diagnostic/environment_variables.rb +1 -1
- data/spec/controllers/job_controller_spec.rb +1 -1
- data/spec/dummy/app/components/gemini/xyz_rule_view.rb +1 -0
- data/spec/dummy/config/application.rb +1 -0
- data/spec/features/enum_spec.rb +35 -100
- data/spec/features/log_view_spec.rb +5 -5
- data/spec/features/rule_spec.rb +30 -30
- data/spec/features/user_view_spec.rb +0 -2
- data/spec/lib/logger_spec.rb +1 -1
- data/spec/models/api_auth_spec.rb +33 -12
- data/spec/models/event_spec.rb +1 -1
- data/spec/models/promise_spec.rb +1 -1
- data/spec/models/user_spec.rb +6 -6
- data/spec/spec_helper.rb +69 -9
- data/spec/support/{shared_connection_db_helpers.rb → clean_db_helpers.rb} +2 -2
- data/spec/support/delayed_job_helpers.rb +1 -1
- data/spec/support/{users.rb → integration_helpers.rb} +9 -11
- data/spec/support/{setup.rb → spec_setup.rb} +6 -19
- data/spec/support/user_helpers.rb +12 -0
- metadata +10 -21
- data/spec/dummy/app/assets/client/application.css +0 -13
- data/spec/dummy/app/assets/client/application.js +0 -15
- data/spec/support/chromedriver.rb +0 -41
- data/spec/support/components/netzke_combobox.rb +0 -57
- data/spec/support/components/netzke_grid.rb +0 -356
- data/spec/support/custom_matchers.rb +0 -18
- data/spec/support/custom_selectors.rb +0 -49
- data/spec/support/download_helper.rb +0 -52
- data/spec/support/helper.rb +0 -20
- data/spec/support/netzke.rb +0 -306
- data/spec/support/performance_helper.rb +0 -26
- data/spec/support/post_run_logger.rb +0 -32
- data/spec/support/shared_connection.rb +0 -31
- data/spec/support/structure_compare.rb +0 -62
- data/spec/support/suite.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d6215dc0386a1fa52611c23d576350432d8dc8867f72dec1a7865717182e9e5
|
4
|
+
data.tar.gz: 66fe4f011556128fe04d5b897f653db57eb6032c4ef3f440ab363c105f0052ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bde7326c5b29b7561371316e43207ded0b9d5b4246b5eb6948aa711eef74fc7e5fbed0fdf5758b61e7eb1549f0109ada0bcfed3910f86dc4e0cf4eeff128153
|
7
|
+
data.tar.gz: 4b2a99929bb2f8fcf4bd75a3b719c3c689dc3cd5e6e04726ea6e6fd07e900bcce821aaec76071d9befd33f604e9a3d4c3884bb0d0051a64669a5dd5c80ccfdd7
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
marty (2.
|
4
|
+
marty (2.4.0)
|
5
5
|
aws-sigv4 (~> 1.0, >= 1.0.2)
|
6
6
|
axlsx (= 3.0.0pre)
|
7
7
|
coderay
|
@@ -106,7 +106,7 @@ GEM
|
|
106
106
|
i18n (0.9.5)
|
107
107
|
concurrent-ruby (~> 1.0)
|
108
108
|
io-like (0.3.0)
|
109
|
-
json-schema (2.8.
|
109
|
+
json-schema (2.8.0)
|
110
110
|
addressable (>= 2.4)
|
111
111
|
loofah (2.2.2)
|
112
112
|
crass (~> 1.0.2)
|
@@ -7,14 +7,37 @@ class Marty::ApiAuthView < Marty::McflyGridPanel
|
|
7
7
|
def configure(c)
|
8
8
|
super
|
9
9
|
|
10
|
-
c.title
|
11
|
-
c.
|
12
|
-
c.
|
10
|
+
c.title = I18n.t('api_auth', default: "API Authorization")
|
11
|
+
c.editing = :in_form
|
12
|
+
c.pagination = :pagination
|
13
|
+
c.model = "Marty::ApiAuth"
|
14
|
+
c.attributes = [:aws, :entity_name, :api_key, :script_name]
|
13
15
|
c.store_config.merge!({sorters: [{property: :app_name, direction: 'ASC'}]})
|
14
16
|
end
|
15
17
|
|
16
|
-
attribute :
|
18
|
+
attribute :aws do |c|
|
19
|
+
c.width = 60
|
20
|
+
c.read_only = true
|
21
|
+
c.text = "AWS"
|
22
|
+
c.type = :boolean
|
23
|
+
c.getter = lambda do |r|
|
24
|
+
!!r.parameters['aws_api_key']
|
25
|
+
end
|
26
|
+
c.sorting_scope = get_json_sorter('parameters', 'aws_api_key')
|
27
|
+
c.filterable = true
|
28
|
+
c.filter_with = lambda do |rel, value, op|
|
29
|
+
rel.where("parameters->>'aws_api_key' IS #{value ? 'NOT' : ''} NULL")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
attribute :entity_name do |c|
|
17
34
|
c.flex = 1
|
35
|
+
c.text = "Entity Name"
|
36
|
+
c.getter = lambda do |r|
|
37
|
+
aws = !!r.parameters['aws_api_key']
|
38
|
+
entity = r.entity
|
39
|
+
entity ? entity.name : (aws ? nil : r.app_name)
|
40
|
+
end
|
18
41
|
end
|
19
42
|
|
20
43
|
attribute :api_key do |c|
|
@@ -12,6 +12,7 @@ class Marty::ApiConfigView < Marty::Grid
|
|
12
12
|
:script,
|
13
13
|
:node,
|
14
14
|
:attr,
|
15
|
+
:api_class,
|
15
16
|
:logged,
|
16
17
|
:input_validated,
|
17
18
|
:output_validated,
|
@@ -19,15 +20,33 @@ class Marty::ApiConfigView < Marty::Grid
|
|
19
20
|
:created_at,
|
20
21
|
:updated_at,
|
21
22
|
]
|
22
|
-
c.paging = :
|
23
|
+
c.paging = :pagination
|
23
24
|
c.editing = :in_form
|
24
25
|
c.store_config.merge!(
|
25
26
|
sorters: [{ property: :script, direction: :ASC},
|
26
|
-
{ property: :node,
|
27
|
-
{ property: :attr,
|
27
|
+
{ property: :node, direction: :ASC},
|
28
|
+
{ property: :attr, direction: :ASC},
|
29
|
+
{ property: :api_class, direction: :ASC},
|
28
30
|
])
|
29
31
|
@model = c.model
|
30
32
|
end
|
33
|
+
|
34
|
+
attribute :api_class do |c|
|
35
|
+
editor_config = {
|
36
|
+
trigger_action: :all,
|
37
|
+
xtype: :combo,
|
38
|
+
store: Marty::Api::Base.class_list,
|
39
|
+
forceSelection: true,
|
40
|
+
}
|
41
|
+
c.merge!(
|
42
|
+
column_config: { editor: editor_config },
|
43
|
+
field_config: editor_config,
|
44
|
+
type: :string,
|
45
|
+
)
|
46
|
+
c.width = 200
|
47
|
+
c.label = "API Class"
|
48
|
+
end
|
49
|
+
|
31
50
|
attribute :script do |c|
|
32
51
|
editor_config = {
|
33
52
|
trigger_action: :all,
|
@@ -43,34 +62,38 @@ class Marty::ApiConfigView < Marty::Grid
|
|
43
62
|
)
|
44
63
|
c.width = 150
|
45
64
|
end
|
65
|
+
|
46
66
|
[:node, :attr].each do |a|
|
47
67
|
attribute a do |c|
|
48
68
|
c.width = 150
|
49
69
|
c.setter = lambda { |r, v| r.send("#{a}=", v.blank? ? nil : v) }
|
50
70
|
end
|
51
71
|
end
|
72
|
+
|
52
73
|
[:logged, :input_validated, :output_validated, :strict_validate].each do
|
53
74
|
|a|
|
54
75
|
attribute a do |c|
|
55
76
|
c.width = 110
|
56
77
|
end
|
57
78
|
end
|
79
|
+
|
58
80
|
[:created_at, :updated_at].each do |a|
|
59
81
|
attribute a do |c|
|
60
82
|
c.read_only = true
|
61
83
|
end
|
62
84
|
end
|
85
|
+
|
63
86
|
def default_form_items
|
64
87
|
[
|
65
88
|
:script,
|
66
89
|
:node,
|
67
90
|
:attr,
|
91
|
+
:api_class,
|
68
92
|
:logged,
|
69
93
|
:input_validated,
|
70
94
|
:output_validated,
|
71
95
|
:strict_validate,
|
72
96
|
]
|
73
97
|
end
|
74
|
-
|
75
98
|
end
|
76
99
|
ApiConfigView = Marty::ApiConfigView
|
@@ -73,8 +73,7 @@ module Layout
|
|
73
73
|
######################################################################
|
74
74
|
# PG ENUM field handling
|
75
75
|
|
76
|
-
def enum_column(c, class_or_array
|
77
|
-
col ||= c.name.demodulize.tableize.singularize
|
76
|
+
def enum_column(c, class_or_array)
|
78
77
|
vals = class_or_array.is_a?(Array) ? class_or_array : class_or_array::VALUES
|
79
78
|
editor_config = {
|
80
79
|
trigger_action: :all,
|
@@ -92,7 +91,6 @@ module Layout
|
|
92
91
|
field_config: editor_config,
|
93
92
|
type: :string,
|
94
93
|
setter: enum_setter(c.name),
|
95
|
-
sorting_scope: get_sorter(col)
|
96
94
|
)
|
97
95
|
end
|
98
96
|
|
@@ -114,10 +112,6 @@ module Layout
|
|
114
112
|
lambda {|r, v| r.send("#{name}=", v.blank? || v == '---' ? nil : v)}
|
115
113
|
end
|
116
114
|
|
117
|
-
def get_sorter(col)
|
118
|
-
lambda {|rel, dir| rel.order("#{col}::text #{dir.to_s}")}
|
119
|
-
end
|
120
|
-
|
121
115
|
######################################################################
|
122
116
|
# employ lots of hakery to implement NULLable boolean field in
|
123
117
|
# Netzke 8.x.
|
@@ -203,4 +197,7 @@ module Layout
|
|
203
197
|
c.align = 'right'
|
204
198
|
end
|
205
199
|
|
200
|
+
def tooltip s1, s2
|
201
|
+
"<span data-qtip=\"#{s2}\">#{s1}</span>"
|
202
|
+
end
|
206
203
|
end; end; end
|
@@ -13,6 +13,28 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
13
13
|
end
|
14
14
|
|
15
15
|
client_class do |c|
|
16
|
+
c.get_component = l(<<-JS)
|
17
|
+
function(name) {
|
18
|
+
return Ext.getCmp(name);
|
19
|
+
}
|
20
|
+
JS
|
21
|
+
|
22
|
+
c.find_component = l(<<-JS)
|
23
|
+
function(name) {
|
24
|
+
return Ext.ComponentQuery.query(`[name=${name}]`)[0];
|
25
|
+
}
|
26
|
+
JS
|
27
|
+
|
28
|
+
c.toggle_component_actions = l(<<-JS)
|
29
|
+
function(prefix, flag) {
|
30
|
+
for (var key in this.actions) {
|
31
|
+
if (key.substring(0, prefix.length) == prefix) {
|
32
|
+
this.actions[key].setDisabled(flag);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
JS
|
37
|
+
|
16
38
|
c.init_component = l(<<-JS)
|
17
39
|
function() {
|
18
40
|
this.dockedItems = this.dockedItems || [];
|
@@ -48,8 +70,7 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
48
70
|
var me = this;
|
49
71
|
|
50
72
|
var children = me.serverConfig.child_components || [];
|
51
|
-
me.
|
52
|
-
'selectionchange',
|
73
|
+
me.onSelectionChange(
|
53
74
|
function(m) {
|
54
75
|
var has_sel = m.hasSelection();
|
55
76
|
|
@@ -66,18 +87,15 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
66
87
|
}
|
67
88
|
|
68
89
|
me.serverConfig.selected = rid;
|
69
|
-
|
70
|
-
for (var key in me.actions) {
|
71
|
-
// hacky -- assumes our functions start with "do"
|
72
|
-
if (key.substring(0, 2) == "do") {
|
73
|
-
me.actions[key].setDisabled(!has_sel);
|
74
|
-
}
|
75
|
-
}
|
90
|
+
me.toggleComponentActions('do', !has_sel);
|
76
91
|
|
77
92
|
for (var child of children) {
|
78
|
-
var comp = me.
|
93
|
+
var comp = me.getComponent(child)
|
79
94
|
if (comp) {
|
80
95
|
comp.serverConfig.parent_id = rid;
|
96
|
+
if (comp.toggleComponentActions) {
|
97
|
+
comp.toggleComponentActions('parent', !has_sel);
|
98
|
+
}
|
81
99
|
if (comp.reload) { comp.reload() }
|
82
100
|
}
|
83
101
|
}
|
@@ -88,7 +106,7 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
88
106
|
for (var event of ['update', 'netzkerefresh']) {
|
89
107
|
store.on(event, function() {
|
90
108
|
for (var link of linked) {
|
91
|
-
var comp = me.
|
109
|
+
var comp = me.findComponent(link);
|
92
110
|
if (comp && comp.reload) { comp.reload() }
|
93
111
|
}
|
94
112
|
}, this);
|
@@ -96,6 +114,15 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
96
114
|
}
|
97
115
|
JS
|
98
116
|
|
117
|
+
c.on_selection_change = l(<<-JS)
|
118
|
+
function(f) {
|
119
|
+
var me = this;
|
120
|
+
me.getSelectionModel().on('selectionchange', function(m) {
|
121
|
+
f(m);
|
122
|
+
});
|
123
|
+
}
|
124
|
+
JS
|
125
|
+
|
99
126
|
c.do_view_in_form = l(<<-JS)
|
100
127
|
function(record){
|
101
128
|
this.netzkeLoadComponent("view_window", {
|
@@ -123,7 +150,7 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
123
150
|
var children = me.serverConfig.child_components || [];
|
124
151
|
this.store.reload();
|
125
152
|
for (child of children) {
|
126
|
-
var comp = me.
|
153
|
+
var comp = me.getComponent(child);
|
127
154
|
if (comp && comp.reload) { comp.reload() }
|
128
155
|
}
|
129
156
|
}
|
@@ -134,13 +161,6 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
134
161
|
this.filters.clearFilters();
|
135
162
|
}
|
136
163
|
JS
|
137
|
-
|
138
|
-
c.netzkeGetComponentFromParent = l(<<-JS)
|
139
|
-
function(component_path) {
|
140
|
-
return this.netzkeGetParentComponent().netzkeGetComponent(component_path);
|
141
|
-
}
|
142
|
-
JS
|
143
|
-
|
144
164
|
end
|
145
165
|
|
146
166
|
######################################################################
|
@@ -168,6 +188,12 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
168
188
|
false
|
169
189
|
end
|
170
190
|
|
191
|
+
action :clear_filters do |a|
|
192
|
+
a.text = "X"
|
193
|
+
a.tooltip = "Clear filters"
|
194
|
+
a.handler = :clear_filters
|
195
|
+
end
|
196
|
+
|
171
197
|
def get_json_sorter(json_col, field)
|
172
198
|
lambda do |r, dir|
|
173
199
|
r.order("#{json_col} ->> '#{field}' " + dir.to_s)
|
@@ -58,7 +58,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
58
58
|
[
|
59
59
|
{
|
60
60
|
text: 'API Management',
|
61
|
-
icon_cls: "fa fa-
|
61
|
+
icon_cls: "fa fa-fighter-jet glyph",
|
62
62
|
disabled: !self.class.has_admin_perm?,
|
63
63
|
menu: [
|
64
64
|
:api_auth_view,
|
@@ -215,17 +215,19 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
215
215
|
end
|
216
216
|
|
217
217
|
action :api_config_view do |a|
|
218
|
-
a.text
|
219
|
-
a.
|
220
|
-
a.
|
221
|
-
a.
|
218
|
+
a.text = 'API Config Management'
|
219
|
+
a.tooltip = 'Manage API behavior and settings'
|
220
|
+
a.handler = :netzke_load_component_by_action
|
221
|
+
a.icon_cls = "fa fa-sliders-h glyph"
|
222
|
+
a.disabled = !self.class.has_admin_perm?
|
222
223
|
end
|
223
224
|
|
224
225
|
action :api_log_view do |a|
|
225
|
-
a.text
|
226
|
-
a.
|
227
|
-
a.
|
228
|
-
a.
|
226
|
+
a.text = 'API Log View'
|
227
|
+
a.tooltip = 'View API logs'
|
228
|
+
a.handler = :netzke_load_component_by_action
|
229
|
+
a.icon_cls = "fa fa-pencil-alt glyph"
|
230
|
+
a.disabled = !self.class.has_admin_perm?
|
229
231
|
end
|
230
232
|
|
231
233
|
action :data_grid_view do |a|
|
@@ -285,7 +287,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
285
287
|
a.disabled = !self.class.has_admin_perm?
|
286
288
|
end
|
287
289
|
|
288
|
-
|
290
|
+
######################################################################
|
289
291
|
|
290
292
|
def bg_command(param)
|
291
293
|
e, root, p = ENV['RAILS_ENV'], Rails.root, Marty::Config["RUBY_PATH"]
|
@@ -480,7 +482,6 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
480
482
|
});
|
481
483
|
}
|
482
484
|
JS
|
483
|
-
|
484
485
|
end
|
485
486
|
|
486
487
|
action :select_posting do |a|
|
@@ -1,63 +1,53 @@
|
|
1
1
|
class Marty::RpcController < ActionController::Base
|
2
2
|
def evaluate
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
params["background"],
|
10
|
-
)
|
11
|
-
respond_to do |format|
|
12
|
-
format.json { send_data res.to_json }
|
13
|
-
format.csv {
|
14
|
-
# SEMI-HACKY: strip outer list if there's only one element.
|
15
|
-
res = res[0] if res.is_a?(Array) && res.length==1
|
16
|
-
send_data Marty::DataExporter.to_csv(res)
|
17
|
-
}
|
18
|
-
end
|
19
|
-
end
|
3
|
+
massaged_params = massage_params(params)
|
4
|
+
api_config = Marty::ApiConfig.lookup(*massaged_params.values_at(
|
5
|
+
:script,
|
6
|
+
:node,
|
7
|
+
:attr)
|
8
|
+
) || {}
|
20
9
|
|
21
|
-
|
22
|
-
|
23
|
-
def get_schema(tag, sname, node, attr)
|
24
|
-
begin
|
25
|
-
Marty::ScriptSet.new(tag).get_engine(sname+'Schemas').
|
26
|
-
evaluate(node, attr, {})
|
27
|
-
rescue => e
|
28
|
-
use_message = e.message == 'No such script' ?
|
29
|
-
'Schema not defined' : 'Problem with schema: ' + e.message
|
30
|
-
raise "Schema error for #{sname}/#{node} attrs=#{attr}: #{use_message}"
|
31
|
-
end
|
32
|
-
end
|
10
|
+
api = api_config.present? ? api_config[:api_class].constantize :
|
11
|
+
Marty::Api::Base
|
33
12
|
|
34
|
-
|
35
|
-
|
36
|
-
return msg unless m
|
37
|
-
"disallowed parameter '#{m[1]}' of type #{m[2]} was received"
|
38
|
-
end
|
13
|
+
api.respond_to(self) do
|
14
|
+
next massaged_params if massaged_params.include?(:error)
|
39
15
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
16
|
+
auth = api.is_authorized?(massaged_params)
|
17
|
+
next {error: "Permission denied"} unless auth
|
18
|
+
|
19
|
+
start_time = Time.zone.now
|
20
|
+
|
21
|
+
api_params = api.process_params(massaged_params)
|
22
|
+
api.before_evaluate(api_params)
|
23
|
+
result = api.evaluate(api_params.deep_dup, request, api_config.deep_dup)
|
24
|
+
api.after_evaluate(api_params.deep_dup, result)
|
25
|
+
|
26
|
+
log_params = {start_time: start_time, auth: auth}
|
27
|
+
api.log(result, api_params + log_params, request) if
|
28
|
+
api_config[:logged]
|
29
|
+
|
30
|
+
result
|
53
31
|
end
|
54
32
|
end
|
55
33
|
|
56
|
-
|
57
|
-
|
58
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
def massage_params request_params
|
37
|
+
sname,
|
38
|
+
tag,
|
39
|
+
node,
|
40
|
+
attr,
|
41
|
+
params,
|
42
|
+
api_key,
|
43
|
+
background = request_params.values_at(:script,
|
44
|
+
:tag,
|
45
|
+
:node,
|
46
|
+
:attrs,
|
47
|
+
:params,
|
48
|
+
:api_key,
|
49
|
+
:background)
|
59
50
|
|
60
|
-
def do_eval(sname, tag, node, attr, params, api_key, background)
|
61
51
|
# FIXME: small patch to allow for single attr array
|
62
52
|
attr = ActiveSupport::JSON.decode(attr) rescue attr
|
63
53
|
|
@@ -66,116 +56,39 @@ class Marty::RpcController < ActionController::Base
|
|
66
56
|
|
67
57
|
# if attr is a single attr array, remember to return as an array
|
68
58
|
if attr.is_a? Array
|
69
|
-
attr
|
59
|
+
attr = attr[0]
|
70
60
|
ret_arr = true
|
71
61
|
end
|
72
62
|
|
73
|
-
start_time = Time.zone.now
|
74
63
|
return {error: "Malformed attrs"} unless attr =~ /\A[a-z][a-zA-Z0-9_]*\z/
|
75
|
-
return {error: "Bad params"} unless params.is_a?(String)
|
76
64
|
|
77
65
|
begin
|
78
|
-
|
79
|
-
|
66
|
+
case params
|
67
|
+
when String
|
68
|
+
params = ActiveSupport::JSON.decode(params)
|
69
|
+
when ActionController::Parameters
|
70
|
+
params.permit!
|
71
|
+
params = JSON.parse(params.to_h.to_json)
|
72
|
+
when nil
|
73
|
+
params = {}
|
74
|
+
else
|
75
|
+
return {error: "Bad params"}
|
76
|
+
end
|
80
77
|
rescue JSON::ParserError => e
|
81
78
|
return {error: "Malformed params"}
|
82
79
|
end
|
83
80
|
|
84
81
|
return {error: "Malformed params"} unless params.is_a?(Hash)
|
85
|
-
need_log,
|
86
|
-
need_input_validate,
|
87
|
-
need_output_validate,
|
88
|
-
need_strict_validate = Marty::ApiConfig.lookup(sname, node, attr)
|
89
|
-
opt = {validate_schema: true,
|
90
|
-
errors_as_objects: true,
|
91
|
-
version: Marty::JsonSchema::RAW_URI }
|
92
|
-
to_append = {"\$schema" => Marty::JsonSchema::RAW_URI}
|
93
|
-
validation_error = nil
|
94
|
-
|
95
|
-
if need_input_validate
|
96
|
-
begin
|
97
|
-
schema = get_schema(tag, sname, node, attr)
|
98
|
-
rescue => e
|
99
|
-
return {error: e.message}
|
100
|
-
end
|
101
|
-
begin
|
102
|
-
er = JSON::Validator.
|
103
|
-
fully_validate(schema.merge(to_append), params, opt)
|
104
|
-
rescue NameError
|
105
|
-
return {error: "Unrecognized PgEnum for attribute #{attr}"}
|
106
|
-
rescue => ex
|
107
|
-
return {error: "#{attr}: #{ex.message}"}
|
108
|
-
end
|
109
|
-
validation_error = get_errors(er) if er.size > 0
|
110
|
-
end
|
111
|
-
return {error: "Error(s) validating: #{validation_error}"} if
|
112
|
-
validation_error
|
113
|
-
|
114
|
-
auth = Marty::ApiAuth.authorized?(sname, api_key)
|
115
|
-
return {error: "Permission denied" } unless auth
|
116
82
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
begin
|
129
|
-
if background
|
130
|
-
result = engine.background_eval(node, params, attr)
|
131
|
-
return retval = {"job_id" => result.__promise__.id}
|
132
|
-
end
|
133
|
-
|
134
|
-
res = engine.evaluate(node, attr, params)
|
135
|
-
|
136
|
-
if need_output_validate && !(res.is_a?(Hash) && res['error'])
|
137
|
-
begin
|
138
|
-
schema = get_schema(tag, sname, node, attr + '_')
|
139
|
-
rescue => e
|
140
|
-
return {error: e.message}
|
141
|
-
end
|
142
|
-
|
143
|
-
begin
|
144
|
-
er = JSON::Validator.fully_validate(schema.merge(to_append), res, opt)
|
145
|
-
rescue NameError
|
146
|
-
return {error: "Unrecognized PgEnum for attribute #{attr}"}
|
147
|
-
rescue => ex
|
148
|
-
return {error: "#{attr}: #{ex.message}"}
|
149
|
-
end
|
150
|
-
|
151
|
-
if er.size > 0
|
152
|
-
errors = er.map{|e| e[:message]}
|
153
|
-
Marty::Logger.error("API #{sname}:#{node}.#{attr}",
|
154
|
-
{error: errors, data: res})
|
155
|
-
res = need_strict_validate ? {error: "Error(s) validating: #{errors}",
|
156
|
-
data: res} : res
|
157
|
-
end
|
158
|
-
end
|
159
|
-
return retval = ret_arr ? [res] : res
|
160
|
-
rescue => exc
|
161
|
-
err_msg = Delorean::Engine.grok_runtime_exception(exc).symbolize_keys
|
162
|
-
logger.info "Evaluation error: #{err_msg}"
|
163
|
-
return retval = err_msg
|
164
|
-
ensure
|
165
|
-
error = Hash === retval ? retval[:error] : nil
|
166
|
-
Marty::Log.write_log('api',
|
167
|
-
"#{sname} - #{node}",
|
168
|
-
{script: sname,
|
169
|
-
node: node,
|
170
|
-
attrs: (ret_arr ? [attr] : attr),
|
171
|
-
input: orig_params,
|
172
|
-
output: error ? nil : retval,
|
173
|
-
start_time: start_time,
|
174
|
-
end_time: Time.zone.now,
|
175
|
-
error: error,
|
176
|
-
remote_ip: request.remote_ip,
|
177
|
-
auth_name: auth
|
178
|
-
}) if need_log.present?
|
179
|
-
end
|
83
|
+
{
|
84
|
+
script: sname,
|
85
|
+
tag: tag,
|
86
|
+
node: node,
|
87
|
+
attr: attr,
|
88
|
+
params: params,
|
89
|
+
api_key: api_key,
|
90
|
+
background: background,
|
91
|
+
return_array: ret_arr
|
92
|
+
}
|
180
93
|
end
|
181
94
|
end
|