marty 3.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.ssh-docker/.keep +0 -0
- data/Dockerfile.dummy +3 -0
- data/Gemfile.lock +1 -1
- data/app/components/marty/data_grid_user_view.rb +39 -0
- data/app/components/marty/data_grid_view.rb +64 -14
- data/app/components/marty/main_auth_app.rb +11 -1
- data/app/components/marty/user_view.rb +3 -9
- data/app/models/marty/data_grid.rb +12 -6
- data/app/models/marty/role_type.rb +14 -1
- data/app/services/marty/data_grid_view/save_grid.rb +2 -2
- data/config/locales/en.yml +11 -2
- data/db/migrate/108_add_data_grid_perms.rb +16 -0
- data/docker-compose.dummy.yml +1 -0
- data/lib/marty/data_conversion.rb +1 -1
- data/lib/marty/migrations.rb +1 -1
- data/lib/marty/version.rb +1 -1
- data/other/marty/diagnostic/aws/ec2_instance.rb +17 -2
- data/other/marty/diagnostic/aws/error.rb +8 -0
- data/spec/dummy/config/application.rb +1 -0
- data/spec/features/data_grid_spec.rb +110 -46
- data/spec/features/rule_spec.rb +1 -1
- data/spec/features/user_view_spec.rb +16 -7
- data/spec/models/data_grid_spec.rb +19 -4
- data/spec/support/netzke.rb +2 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdb72d97f91a1f370754d64b41ca268addf4f001b061cc3e531f5993d7f5dae7
|
4
|
+
data.tar.gz: 1cefbf2a2e8d6e1176be63e876f7207fbc1fe8c07dd8b78b182ac4621e9f638b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c82561e607fcb7ffd5e154e85279c7afd1c992867d495cee261310282fa55912247b09db6bff1d88d773a3e49fac0fe5f361fc2048c4f8cd4ea5f70a3d70db2c
|
7
|
+
data.tar.gz: 540081cb0f2474a32ebb47a5fc42741cedc717d2dc71ebc7bb772af7a8c24c475db5c6812b403b29b2997b95c1123ba576997b95af5cc84f5b1afa9163bc7168
|
data/.gitignore
CHANGED
data/.ssh-docker/.keep
ADDED
File without changes
|
data/Dockerfile.dummy
CHANGED
@@ -24,6 +24,9 @@ RUN curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrom
|
|
24
24
|
&& sed -i 's|HERE/chrome\"|HERE/chrome\" --disable-setuid-sandbox|g' /opt/google/chrome/google-chrome \
|
25
25
|
&& rm google-chrome.deb
|
26
26
|
|
27
|
+
# Install additional tools
|
28
|
+
RUN apt-get install -qq -y --no-install-recommends netcat-openbsd vim
|
29
|
+
|
27
30
|
RUN gem install bundler
|
28
31
|
|
29
32
|
ENV BUNDLE_PATH /bundle_box/bundle
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Marty
|
2
|
+
class DataGridUserView < DataGridView
|
3
|
+
has_marty_permissions read: [:data_grid_editor, :admin, :dev]
|
4
|
+
|
5
|
+
def configure(c)
|
6
|
+
super
|
7
|
+
|
8
|
+
c.attributes =
|
9
|
+
[
|
10
|
+
:name,
|
11
|
+
:created_dt,
|
12
|
+
]
|
13
|
+
c.editing = :inline
|
14
|
+
end
|
15
|
+
|
16
|
+
def default_bbar
|
17
|
+
[:edit_grid]
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_records(params)
|
21
|
+
cur_perms = Mcfly.whodunnit.roles.map(&:to_sym)
|
22
|
+
model.where("permissions->'view' ?| ARRAY[:roles] OR "\
|
23
|
+
"permissions->'edit_data' ?| ARRAY[:roles] OR "\
|
24
|
+
"permissions->'edit_all' ?| ARRAY[:roles]",
|
25
|
+
roles: cur_perms).scoping do
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_edit_permission(permissions)
|
31
|
+
cur_perms = current_user_roles.map(&:to_s)
|
32
|
+
['edit_all', 'edit_data', 'view'].detect do |p|
|
33
|
+
permissions[p] - cur_perms != permissions[p]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
DataGridUserView = Marty::DataGridUserView
|
@@ -98,6 +98,9 @@ module Marty; class DataGridView < McflyGridPanel
|
|
98
98
|
:lenient,
|
99
99
|
:data_type,
|
100
100
|
:constraint,
|
101
|
+
:perm_view,
|
102
|
+
:perm_edit_data,
|
103
|
+
:perm_edit_all,
|
101
104
|
:created_dt,
|
102
105
|
]
|
103
106
|
|
@@ -107,6 +110,19 @@ module Marty; class DataGridView < McflyGridPanel
|
|
107
110
|
c.multi_select = false
|
108
111
|
end
|
109
112
|
|
113
|
+
def set_perms(dg, data)
|
114
|
+
permstrs = %w[perm_view perm_edit_data perm_edit_all]
|
115
|
+
view, edit_data, edit_all = data.values_at(*permstrs).map do |plist|
|
116
|
+
Marty::RoleType.from_nice_names(plist)
|
117
|
+
end
|
118
|
+
dg.permissions = {
|
119
|
+
view: view.present? ? view : [],
|
120
|
+
edit_data: edit_data.present? ? edit_data : [],
|
121
|
+
edit_all: edit_all.present? ? edit_all : [],
|
122
|
+
}
|
123
|
+
dg.save!
|
124
|
+
end
|
125
|
+
|
110
126
|
endpoint :add_window__add_form__submit do |params|
|
111
127
|
data = ActiveSupport::JSON.decode(params[:data])
|
112
128
|
|
@@ -114,7 +130,8 @@ module Marty; class DataGridView < McflyGridPanel
|
|
114
130
|
!config[:permissions][:create]
|
115
131
|
|
116
132
|
begin
|
117
|
-
DataGrid.create_from_import(data['name'], data['export'])
|
133
|
+
dg = DataGrid.create_from_import(data['name'], data['export'])
|
134
|
+
set_perms(dg, data)
|
118
135
|
client.success = true
|
119
136
|
client.netzke_on_submit_success
|
120
137
|
rescue StandardError => exc
|
@@ -129,6 +146,7 @@ module Marty; class DataGridView < McflyGridPanel
|
|
129
146
|
|
130
147
|
begin
|
131
148
|
dg.update_from_import(data['name'], data['export'])
|
149
|
+
set_perms(dg, data)
|
132
150
|
client.success = true
|
133
151
|
client.netzke_on_submit_success
|
134
152
|
rescue StandardError => exc
|
@@ -168,14 +186,8 @@ module Marty; class DataGridView < McflyGridPanel
|
|
168
186
|
client.netzke_client_show_grid maxcount, res, 'Data Grid'
|
169
187
|
end
|
170
188
|
|
171
|
-
|
172
|
-
|
173
|
-
def self.get_edit_edit_permission
|
174
|
-
Marty::Config['grid_edit_edit_perm'] || 'edit_all'
|
175
|
-
end
|
176
|
-
|
177
|
-
def self.get_edit_save_permission
|
178
|
-
Marty::Config['grid_edit_save_perm'] || 'edit_all'
|
189
|
+
def self.get_edit_permission(_permissions)
|
190
|
+
'edit_all'
|
179
191
|
end
|
180
192
|
|
181
193
|
endpoint :edit_grid do |params|
|
@@ -193,9 +205,21 @@ module Marty; class DataGridView < McflyGridPanel
|
|
193
205
|
vdim = md.map { |m| m['dir'] == 'v' && m['attr'] }.select { |v| v }
|
194
206
|
hdim_en = hdim.map { |d| I18n.t('attributes.' + d, default: d) }
|
195
207
|
vdim_en = vdim.map { |d| I18n.t('attributes.' + d, default: d) }
|
196
|
-
|
197
|
-
|
198
|
-
client.
|
208
|
+
perm = self.class.get_edit_permission(dg.permissions)
|
209
|
+
# should never happen
|
210
|
+
return client.netzke_notify('No permission to edit/view grid.') unless perm
|
211
|
+
|
212
|
+
doing = case perm
|
213
|
+
when 'view'
|
214
|
+
'Viewing'
|
215
|
+
when 'edit_all'
|
216
|
+
'Editing (all)'
|
217
|
+
when 'edit_data'
|
218
|
+
'Editing (data only)'
|
219
|
+
end
|
220
|
+
name = "#{doing} Data Grid '#{dg.name}'"
|
221
|
+
|
222
|
+
client.edit_grid(record_id, hdim_en, vdim_en, res, name, perm)
|
199
223
|
end
|
200
224
|
|
201
225
|
endpoint :save_grid do |params|
|
@@ -213,10 +237,36 @@ module Marty; class DataGridView < McflyGridPanel
|
|
213
237
|
def default_form_items
|
214
238
|
[
|
215
239
|
:name,
|
240
|
+
:perm_view, :perm_edit_data, :perm_edit_all,
|
216
241
|
textarea_field(:export, height: 300, hide_label: true),
|
217
242
|
]
|
218
243
|
end
|
219
244
|
|
245
|
+
['view', 'edit_data', 'edit_all'].each do |p|
|
246
|
+
s = ('perm_' + p).to_s
|
247
|
+
attribute s do |c|
|
248
|
+
c.width = 100
|
249
|
+
c.flex = 1
|
250
|
+
c.label = I18n.t("data_grid_view_perms.#{s}")
|
251
|
+
c.type = :string
|
252
|
+
c.getter = lambda do |r|
|
253
|
+
Marty::RoleType.to_nice_names(r.permissions[p].sort)
|
254
|
+
end
|
255
|
+
store = Marty::RoleType.to_nice_names(::Marty::RoleType.get_all.sort.map)
|
256
|
+
|
257
|
+
# edit does not work without this dummy setter
|
258
|
+
c.setter = ->(r, v) {}
|
259
|
+
|
260
|
+
c.editor_config = {
|
261
|
+
multi_select: true,
|
262
|
+
empty_text: I18n.t('user_grid.select_roles'),
|
263
|
+
store: store,
|
264
|
+
type: :string,
|
265
|
+
xtype: :combo,
|
266
|
+
}
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
220
270
|
component :edit_window do |c|
|
221
271
|
super(c)
|
222
272
|
c.width = 700
|
@@ -228,11 +278,11 @@ module Marty; class DataGridView < McflyGridPanel
|
|
228
278
|
end
|
229
279
|
|
230
280
|
attribute :name do |c|
|
231
|
-
c.width =
|
281
|
+
c.width = 400
|
232
282
|
end
|
233
283
|
|
234
284
|
attribute :constraint do |c|
|
235
|
-
c.width =
|
285
|
+
c.width = 150
|
236
286
|
end
|
237
287
|
|
238
288
|
attribute :hcols do |c|
|
@@ -4,6 +4,7 @@ require 'marty/api_log_view'
|
|
4
4
|
require 'marty/config_view'
|
5
5
|
require 'marty/data_grid_view'
|
6
6
|
require 'marty/schedule_jobs_dashboard'
|
7
|
+
require 'marty/data_grid_user_view'
|
7
8
|
require 'marty/event_view'
|
8
9
|
require 'marty/import_type_view'
|
9
10
|
require 'marty/new_posting_window'
|
@@ -96,6 +97,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
96
97
|
icon_cls: 'fa fa-window-restore glyph',
|
97
98
|
menu: [
|
98
99
|
:data_grid_view,
|
100
|
+
:data_grid_user_view,
|
99
101
|
:reporting,
|
100
102
|
:scripting,
|
101
103
|
:promise_view,
|
@@ -237,7 +239,14 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
237
239
|
end
|
238
240
|
|
239
241
|
action :data_grid_view do |a|
|
240
|
-
a.text = I18n.t('data_grid_view'
|
242
|
+
a.text = I18n.t('data_grid_view')
|
243
|
+
a.handler = :netzke_load_component_by_action
|
244
|
+
a.icon_cls = 'fa fa-table glyph'
|
245
|
+
a.disabled = !self.class.has_any_perm?
|
246
|
+
end
|
247
|
+
|
248
|
+
action :data_grid_user_view do |a|
|
249
|
+
a.text = I18n.t('data_grid_user_view')
|
241
250
|
a.handler = :netzke_load_component_by_action
|
242
251
|
a.icon_cls = 'fa fa-table glyph'
|
243
252
|
a.disabled = !self.class.has_any_perm?
|
@@ -388,6 +397,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
388
397
|
component :config_view
|
389
398
|
|
390
399
|
component :data_grid_view
|
400
|
+
component :data_grid_user_view
|
391
401
|
|
392
402
|
component :event_view
|
393
403
|
|
@@ -33,9 +33,7 @@ module Marty; class UserView < Marty::Grid
|
|
33
33
|
def self.set_roles(roles, user)
|
34
34
|
roles = [] unless roles.present?
|
35
35
|
|
36
|
-
roles = Marty::RoleType.
|
37
|
-
roles.include?(I18n.t("roles.#{role}", default: role))
|
38
|
-
end
|
36
|
+
roles = ::Marty::RoleType.from_nice_names(roles)
|
39
37
|
|
40
38
|
roles_in_user = user.user_roles.map(&:role)
|
41
39
|
roles_to_delete = roles_in_user - roles
|
@@ -152,14 +150,10 @@ module Marty; class UserView < Marty::Grid
|
|
152
150
|
c.type = :string
|
153
151
|
|
154
152
|
c.getter = lambda do |r|
|
155
|
-
r.user_roles.map
|
156
|
-
I18n.t("roles.#{ur.role}", default: ur.role)
|
157
|
-
end
|
153
|
+
Marty::RoleType.to_nice_names(r.user_roles.map(&:role))
|
158
154
|
end
|
159
155
|
|
160
|
-
store = ::Marty::RoleType.
|
161
|
-
I18n.t("roles.#{role}", default: role)
|
162
|
-
end
|
156
|
+
store = ::Marty::RoleType.to_nice_names(::Marty::RoleType::VALUES.sort)
|
163
157
|
|
164
158
|
c.editor_config = {
|
165
159
|
multi_select: true,
|
@@ -360,13 +360,19 @@ class Marty::DataGrid < Marty::Base
|
|
360
360
|
def export_array
|
361
361
|
# add data type metadata row if not default
|
362
362
|
lenstr = 'lenient' if lenient
|
363
|
-
typestr = data_type unless [nil, DEFAULT_DATA_TYPE].member?(data_type) &&
|
364
|
-
!constraint.present?
|
365
363
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
364
|
+
typestr = data_type unless [nil, DEFAULT_DATA_TYPE].member?(data_type)
|
365
|
+
len_type = [lenstr, typestr].compact.join(' ')
|
366
|
+
|
367
|
+
meta_rows = if (lenient || typestr) && constraint
|
368
|
+
[[len_type, constraint]]
|
369
|
+
elsif lenient || typestr
|
370
|
+
[[len_type]]
|
371
|
+
elsif constraint
|
372
|
+
[['', constraint]]
|
373
|
+
else
|
374
|
+
[]
|
375
|
+
end
|
370
376
|
|
371
377
|
meta_rows += metadata.map do |inf|
|
372
378
|
[inf['attr'], inf['type'], inf['dir'], inf['rs_keep'] || '']
|
@@ -5,6 +5,19 @@ class Marty::RoleType < Marty::Base
|
|
5
5
|
'admin',
|
6
6
|
'user_manager',
|
7
7
|
'dev',
|
8
|
-
'viewer'
|
8
|
+
'viewer',
|
9
|
+
'data_grid_editor'
|
9
10
|
]
|
11
|
+
|
12
|
+
def self.from_nice_names(roles)
|
13
|
+
Marty::RoleType.get_all.select do |role|
|
14
|
+
roles.include?(I18n.t("roles.#{role}", default: role))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.to_nice_names(roles)
|
19
|
+
roles.map do |role|
|
20
|
+
I18n.t("roles.#{role}", default: role)
|
21
|
+
end
|
22
|
+
end
|
10
23
|
end
|
@@ -15,8 +15,9 @@ module Marty
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.call(params)
|
18
|
-
user_perm = Marty::DataGridView.get_edit_save_permission
|
19
18
|
rec_id = params['record_id']
|
19
|
+
dg = Marty::DataGrid.mcfly_pt('infinity').find_by(group_id: rec_id)
|
20
|
+
user_perm = Marty::DataGridView.get_edit_permission(dg.permissions)
|
20
21
|
data = params['data']
|
21
22
|
raise GridError.new('entered with view permissions', data, rec_id) if
|
22
23
|
user_perm == 'view'
|
@@ -24,7 +25,6 @@ module Marty
|
|
24
25
|
data_as_array = data.map do |row|
|
25
26
|
row.keys.map { |key| row[key] }
|
26
27
|
end
|
27
|
-
dg = Marty::DataGrid.mcfly_pt('infinity').find_by(group_id: rec_id)
|
28
28
|
vcnt = dg.metadata.select { |md| md['dir'] == 'v' }.count
|
29
29
|
hcnt = dg.metadata.select { |md| md['dir'] == 'h' }.count
|
30
30
|
cur_data_dim = [dg.data.length, dg.data[0].length]
|
data/config/locales/en.yml
CHANGED
@@ -18,8 +18,10 @@ en:
|
|
18
18
|
create_posting: Create
|
19
19
|
api_auth: API Authorization
|
20
20
|
event_view: Event View
|
21
|
-
data_grid_view: Data Grids
|
22
|
-
data_grid: Data Grids
|
21
|
+
data_grid_view: Data Grids Admin
|
22
|
+
data_grid: Data Grids Admin
|
23
|
+
data_grid_user: Data Grids
|
24
|
+
data_grid_user_view: Data Grids
|
23
25
|
|
24
26
|
data_import_view:
|
25
27
|
import: Import
|
@@ -30,6 +32,7 @@ en:
|
|
30
32
|
admin: Admin
|
31
33
|
dev: Developer
|
32
34
|
user_manager: User Manager
|
35
|
+
data_grid_editor: Data Grid Editor
|
33
36
|
|
34
37
|
posting_types:
|
35
38
|
BASE: BASE
|
@@ -176,3 +179,9 @@ en:
|
|
176
179
|
grid:
|
177
180
|
base:
|
178
181
|
view_record: "%{model} (Read-only)"
|
182
|
+
|
183
|
+
data_grid_view_perms:
|
184
|
+
perm_view: Can View
|
185
|
+
perm_edit_data: Can Edit Data
|
186
|
+
perm_edit_all: Can Edit All
|
187
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class AddDataGridPerms < ActiveRecord::Migration[4.2]
|
2
|
+
def self.up
|
3
|
+
default = {
|
4
|
+
view: [],
|
5
|
+
edit_data: [],
|
6
|
+
edit_all: []
|
7
|
+
}
|
8
|
+
table = :marty_data_grids
|
9
|
+
add_column table, :permissions, :jsonb, null: false, default: default
|
10
|
+
add_index table, "(permissions->'view')", using: "GIN",
|
11
|
+
name: :marty_data_grids_perm_idx
|
12
|
+
end
|
13
|
+
def self.down
|
14
|
+
remove_column :marty_data_grids, :permissions
|
15
|
+
end
|
16
|
+
end
|
data/docker-compose.dummy.yml
CHANGED
data/lib/marty/migrations.rb
CHANGED
data/lib/marty/version.rb
CHANGED
@@ -35,15 +35,30 @@ class Marty::Diagnostic::Aws::Ec2Instance < Marty::Aws::Request
|
|
35
35
|
|
36
36
|
def ec2_request action, params = {}
|
37
37
|
resp = request({ action: action }, params)
|
38
|
-
Hash.from_xml(resp)
|
38
|
+
parsed = Hash.from_xml(resp)
|
39
|
+
|
40
|
+
# check AWS response for errors
|
41
|
+
error = parsed.dig('Response', 'Errors', 'Error')
|
42
|
+
raise Marty::Diagnostic::Aws::Error.new(action, error) if error
|
43
|
+
|
44
|
+
action_resp = parsed["#{action}Response"]
|
45
|
+
raise Marty::Diagnostic::Aws::Error.new(action, parsed) unless action_resp
|
46
|
+
|
47
|
+
action_resp
|
39
48
|
end
|
40
49
|
|
41
50
|
def get_tag
|
51
|
+
action = 'DescribeTags'
|
42
52
|
params = { 'Filter.1.Name' => 'resource-id',
|
43
53
|
'Filter.1.Value.1' => get_instance_id,
|
44
54
|
'Filter.2.Name' => 'key',
|
45
55
|
'Filter.2.Value.1' => 'Name' }
|
46
|
-
|
56
|
+
|
57
|
+
action_resp = ec2_request(action, params)
|
58
|
+
tag = action_resp.dig('tagSet', 'item', 'value')
|
59
|
+
raise Marty::Diagnostic::Aws::Error.new(action, action_resp) unless tag
|
60
|
+
|
61
|
+
tag
|
47
62
|
end
|
48
63
|
|
49
64
|
def get_instances
|
@@ -2,6 +2,10 @@ require 'spec_helper'
|
|
2
2
|
require 'marty_rspec'
|
3
3
|
|
4
4
|
feature 'data grid view', js: true do
|
5
|
+
before(:all) do
|
6
|
+
self.use_transactional_tests = true
|
7
|
+
end
|
8
|
+
|
5
9
|
before(:each) do
|
6
10
|
marty_whodunnit
|
7
11
|
Marty::Script.load_scripts
|
@@ -11,12 +15,22 @@ feature 'data grid view', js: true do
|
|
11
15
|
n = File.basename(path, '.txt').camelize
|
12
16
|
Marty::DataGrid.create_from_import(n, File.read(path), dt)
|
13
17
|
end
|
18
|
+
u = Marty::User.create!(login: 'grid_user',
|
19
|
+
firstname: 'grid',
|
20
|
+
lastname: 'user',
|
21
|
+
active: true)
|
22
|
+
Marty::UserRole.create!(user_id: u.id, role: 'data_grid_editor')
|
23
|
+
@no_perm = { 'view' => [],
|
24
|
+
'edit_data' => [],
|
25
|
+
'edit_all' => [] }
|
14
26
|
end
|
15
27
|
|
16
|
-
def go_to_data_grids
|
28
|
+
def go_to_data_grids(admin: true)
|
29
|
+
log_in_as(admin ? 'marty' : 'grid_user')
|
17
30
|
press('Applications')
|
18
|
-
|
19
|
-
|
31
|
+
dest = 'Data Grids' + (admin ? ' Admin' : '')
|
32
|
+
press(dest)
|
33
|
+
expect(page).to have_content dest
|
20
34
|
end
|
21
35
|
|
22
36
|
# setup the info for the ext grid
|
@@ -24,7 +38,7 @@ feature 'data grid view', js: true do
|
|
24
38
|
widths, rows = get_grid_info
|
25
39
|
@grid = page.all(:xpath,
|
26
40
|
".//div[contains(@class, 'x-grid-item-container')]").
|
27
|
-
reject { |e| e.text.include?('
|
41
|
+
reject { |e| e.text.include?('DataGrid1') }.first
|
28
42
|
@gridx = @grid.native.rect.x
|
29
43
|
@gridy = @grid.native.rect.y
|
30
44
|
height = @grid.native.size.height
|
@@ -278,18 +292,97 @@ feature 'data grid view', js: true do
|
|
278
292
|
expect(grid_meta).to eq(exp_meta)
|
279
293
|
end
|
280
294
|
|
281
|
-
it 'dg
|
295
|
+
it 'dg perms' do
|
282
296
|
log_in_as('marty')
|
283
297
|
go_to_data_grids
|
284
298
|
dgv = netzke_find('data_grid_view')
|
285
299
|
grids = dgv.get_col_vals('name', 5)
|
286
|
-
|
287
|
-
|
300
|
+
set_one = lambda do |grid, perms|
|
301
|
+
pos = grids.index(grid) + 1
|
302
|
+
dgv.select_row(pos)
|
303
|
+
press('Edit')
|
304
|
+
wait_for_ajax
|
305
|
+
view_combo = netzke_find('Can View', 'combobox')
|
306
|
+
edit_data_combo = netzke_find('Can Edit Data', 'combobox')
|
307
|
+
edit_all_combo = netzke_find('Can Edit All', 'combobox')
|
308
|
+
view_combo.select_values(perms['view'].join(', '))
|
309
|
+
edit_data_combo.select_values(perms['edit_data'].join(', '))
|
310
|
+
edit_all_combo.select_values(perms['edit_all'].join(', '))
|
311
|
+
press('OK')
|
312
|
+
wait_for_ajax
|
313
|
+
end
|
314
|
+
dg1p = { 'view' => ['Data Grid Editor'],
|
315
|
+
'edit_data' => ['Data Grid Editor'],
|
316
|
+
'edit_all' => ['Admin'] }
|
317
|
+
dg2p = { 'view' => ['Data Grid Editor', 'User Manager'],
|
318
|
+
'edit_data' => ['Data Grid Editor', 'User Manager'],
|
319
|
+
'edit_all' => ['Data Grid Editor', 'Admin'] }
|
320
|
+
set_one.call('DataGrid1', dg1p)
|
321
|
+
set_one.call('DataGrid2', dg2p)
|
322
|
+
dg1 = Marty::DataGrid.mcfly_pt('infinity').find_by(name: 'DataGrid1')
|
323
|
+
dg2 = Marty::DataGrid.mcfly_pt('infinity').find_by(name: 'DataGrid2')
|
324
|
+
fixexp = lambda do |orig_h|
|
325
|
+
orig_h.each_with_object({}) do |(k, v), h|
|
326
|
+
h[k] = v.map do |vals|
|
327
|
+
vals.split(' ').map(&:downcase).join('_')
|
328
|
+
end.sort
|
329
|
+
end
|
330
|
+
end
|
331
|
+
exp1 = fixexp.call(dg1p)
|
332
|
+
exp2 = fixexp.call(dg2p)
|
333
|
+
fixgot = ->(orig_h) { Hash[orig_h.map { |k, v| [k, v.sort] }] }
|
334
|
+
got1 = fixgot.call(dg1.permissions)
|
335
|
+
got2 = fixgot.call(dg2.permissions)
|
336
|
+
cmp1 = struct_compare(got1, exp1)
|
337
|
+
cmp2 = struct_compare(got2, exp2)
|
338
|
+
expect(cmp1).to be_falsey
|
339
|
+
expect(cmp2).to be_falsey
|
340
|
+
|
341
|
+
set_one.call('DataGrid1', @no_perm)
|
342
|
+
set_one.call('DataGrid2', @no_perm)
|
343
|
+
dg1 = Marty::DataGrid.mcfly_pt('infinity').find_by(name: 'DataGrid1')
|
344
|
+
dg2 = Marty::DataGrid.mcfly_pt('infinity').find_by(name: 'DataGrid2')
|
345
|
+
expect(dg1.permissions).to eq(@no_perm)
|
346
|
+
expect(dg2.permissions).to eq(@no_perm)
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'show grid' do
|
350
|
+
log_in_as('marty')
|
351
|
+
go_to_data_grids
|
352
|
+
dgv = netzke_find('data_grid_view')
|
353
|
+
grids = dgv.get_col_vals('name', 5)
|
354
|
+
pos = grids.index('DataGrid1') + 1
|
355
|
+
dgv.select_row(pos)
|
356
|
+
press('Show Grid')
|
357
|
+
expect(page).to have_content('Antwerp')
|
358
|
+
end
|
359
|
+
|
360
|
+
def set_perm(perm)
|
361
|
+
p = @no_perm + (perm ? { perm => ['data_grid_editor'] } : {})
|
362
|
+
Marty::DataGrid.mcfly_pt('infinity').each do |dg|
|
363
|
+
dg.permissions = p
|
364
|
+
dg.save!
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'dg context menus' do
|
369
|
+
log_in_as('grid_user')
|
370
|
+
go_to_data_grids(admin: false)
|
371
|
+
dgv = netzke_find('data_grid_user_view')
|
372
|
+
context_test_all = ENV['DG_FEATURE_FULL'] == 'true'
|
373
|
+
[[nil, nil],
|
374
|
+
['edit_all', context_test_all],
|
288
375
|
['edit_data', false],
|
289
376
|
['view', false]].each do |perm, all_cells|
|
377
|
+
|
378
|
+
set_perm(perm)
|
379
|
+
press('Refresh')
|
380
|
+
grids = dgv.get_col_vals('name', 5)
|
381
|
+
if perm.nil?
|
382
|
+
expect(grids).to be_nil
|
383
|
+
next
|
384
|
+
end
|
290
385
|
grids.each do |grid|
|
291
|
-
Marty::Config['grid_edit_edit_perm'] = perm
|
292
|
-
Marty::Config['grid_edit_save_perm'] = perm
|
293
386
|
pos = grids.index(grid) + 1
|
294
387
|
dgv.select_row(pos)
|
295
388
|
press('Edit Grid')
|
@@ -300,8 +393,14 @@ feature 'data grid view', js: true do
|
|
300
393
|
wait_for_ajax
|
301
394
|
end
|
302
395
|
end
|
303
|
-
|
304
|
-
|
396
|
+
end
|
397
|
+
|
398
|
+
it 'dg editor' do
|
399
|
+
set_perm('edit_all')
|
400
|
+
log_in_as('grid_user')
|
401
|
+
go_to_data_grids(admin: false)
|
402
|
+
dgv = netzke_find('data_grid_user_view')
|
403
|
+
grids = dgv.get_col_vals('name', 5)
|
305
404
|
|
306
405
|
# now test some editing, saving, and cancel logic
|
307
406
|
get_latest = lambda do
|
@@ -460,40 +559,5 @@ feature 'data grid view', js: true do
|
|
460
559
|
press('Save')
|
461
560
|
sleep 1
|
462
561
|
validate_grid('1')
|
463
|
-
|
464
|
-
Marty::Config['grid_edit_save_perm'] = 'view'
|
465
|
-
pos = grids.index('DataGrid5') + 1
|
466
|
-
dgv.select_row(pos)
|
467
|
-
count = 1
|
468
|
-
begin
|
469
|
-
press('Edit Grid')
|
470
|
-
wait_for_ajax
|
471
|
-
grid_setup
|
472
|
-
cell_edit(2, 3, '123.456')
|
473
|
-
rescue StandardError => e
|
474
|
-
if count > 0
|
475
|
-
sleep 1
|
476
|
-
retry
|
477
|
-
end
|
478
|
-
count -= 1
|
479
|
-
end
|
480
|
-
press('Save')
|
481
|
-
errexp = 'error: save_grid: entered with view permissions'
|
482
|
-
expect(page).to have_content(errexp)
|
483
|
-
press('OK')
|
484
|
-
wait_for_ajax
|
485
|
-
context_click(2, 4, 4, click: true)
|
486
|
-
Marty::Config['grid_edit_save_perm'] = 'edit_data'
|
487
|
-
press('Save')
|
488
|
-
errexp = 'error: save_grid: grid modification not allowed'
|
489
|
-
expect(page).to have_content(errexp)
|
490
|
-
exp_log = JSON.parse(File.read('spec/fixtures/misc/grid_log_errs.json'))
|
491
|
-
got = Marty::Log.all.select(:message, :details).attributes.map do |l|
|
492
|
-
newl = l.except('id')
|
493
|
-
newl['details'].delete('rec_id')
|
494
|
-
newl
|
495
|
-
end
|
496
|
-
cmp = struct_compare(got, exp_log)
|
497
|
-
expect(cmp).to be_falsey
|
498
562
|
end
|
499
563
|
end
|
data/spec/features/rule_spec.rb
CHANGED
@@ -419,7 +419,7 @@ EOL
|
|
419
419
|
%Q({"grid1":"DataGrid1"}),
|
420
420
|
%Q({"grid1":"DataGrid1"})])
|
421
421
|
press('Applications')
|
422
|
-
press('Data Grids')
|
422
|
+
press('Data Grids Admin')
|
423
423
|
dgv = netzke_find('data_grid_view')
|
424
424
|
cvs = dgv.get_col_vals(:name, 4, 0)
|
425
425
|
ind1 = cvs.index('DataGrid1') + 1
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
feature 'under
|
3
|
+
feature 'under System menu, User Management worflows', js: true do
|
4
4
|
def go_to_user_view
|
5
5
|
press('System')
|
6
6
|
press('User Management')
|
@@ -77,6 +77,7 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
77
77
|
|
78
78
|
and_by 'check row got edited' do
|
79
79
|
wait_for_ajax
|
80
|
+
r2 = user_view.get_row_vals(2)
|
80
81
|
expect(user_view.get_row_vals(2)).to netzke_include(
|
81
82
|
login: 'new_login',
|
82
83
|
firstname: 'new_fname',
|
@@ -114,6 +115,9 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
114
115
|
by 'check buttons' do
|
115
116
|
find(:btn, 'New User', match: :first)
|
116
117
|
user_view.select_row(1)
|
118
|
+
expect { find(:btn, 'New User') }.not_to raise_error
|
119
|
+
expect { find(:btn, 'Edit') }.not_to raise_error
|
120
|
+
expect { find(:btn, 'Delete') }.not_to raise_error
|
117
121
|
expect(btn_disabled?('New User')).to be_falsy
|
118
122
|
expect(btn_disabled?('Edit')).to be_falsy
|
119
123
|
expect(btn_disabled?('Delete')).to be_falsy
|
@@ -127,6 +131,9 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
127
131
|
by 'check buttons' do
|
128
132
|
find(:btn, 'New User', match: :first)
|
129
133
|
user_view.select_row(1)
|
134
|
+
expect { find(:btn, 'New User') }.not_to raise_error
|
135
|
+
expect { find(:btn, 'Edit') }.not_to raise_error
|
136
|
+
expect { find(:btn, 'Delete') }.not_to raise_error
|
130
137
|
expect(btn_disabled?('New User')).to be_falsy
|
131
138
|
expect(btn_disabled?('Edit')).to be_falsy
|
132
139
|
expect(btn_disabled?('Delete')).to be_falsy
|
@@ -140,9 +147,10 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
140
147
|
user_view = netzke_find('user_view')
|
141
148
|
by 'check buttons' do
|
142
149
|
user_view.select_row(1)
|
143
|
-
|
144
|
-
expect(
|
145
|
-
expect(
|
150
|
+
err = /Unable to find visible btn/
|
151
|
+
expect { find(:btn, 'New User') }.to raise_error(err)
|
152
|
+
expect { find(:btn, 'Edit') }.to raise_error(err)
|
153
|
+
expect { find(:btn, 'Delete') }.to raise_error(err)
|
146
154
|
end
|
147
155
|
end
|
148
156
|
|
@@ -153,9 +161,10 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
153
161
|
user_view = netzke_find('user_view')
|
154
162
|
by 'check buttons' do
|
155
163
|
user_view.select_row(1)
|
156
|
-
|
157
|
-
expect(
|
158
|
-
expect(
|
164
|
+
err = /Unable to find visible btn/
|
165
|
+
expect { find(:btn, 'New User') }.to raise_error(err)
|
166
|
+
expect { find(:btn, 'Edit') }.to raise_error(err)
|
167
|
+
expect { find(:btn, 'Delete') }.to raise_error(err)
|
159
168
|
end
|
160
169
|
end
|
161
170
|
end
|
@@ -814,7 +814,8 @@ EOS
|
|
814
814
|
# rubocop:disable Style/NestedTernaryOperator
|
815
815
|
type_str = type == 'float' ? (explicit_float ? 'float' : nil) : type
|
816
816
|
# rubocop:enable Style/NestedTernaryOperator
|
817
|
-
|
817
|
+
con_part = constraint.present? ? "\t" + constraint : ''
|
818
|
+
top = [lenient_str, type_str].compact.join(' ') + con_part + "\n"
|
818
819
|
(top =~ /\A\s*\z/ ? '' : top) +
|
819
820
|
<<~EOS
|
820
821
|
b\tboolean\tv
|
@@ -836,8 +837,8 @@ EOS
|
|
836
837
|
tests = JSON.parse(File.read('spec/fixtures/json/data_grid.json'))
|
837
838
|
aggregate_failures do
|
838
839
|
tests.each do |test|
|
839
|
-
keys = %w[id type constraint values error]
|
840
|
-
id, type, constraint, values, error = test.values_at(*keys)
|
840
|
+
keys = %w[id type constraint values error line1]
|
841
|
+
id, type, constraint, values, error, line1 = test.values_at(*keys)
|
841
842
|
err_re = Regexp.new(error) if error
|
842
843
|
# for float, do both ex- and implicit declaration
|
843
844
|
exfls = type == 'float' ? [true, false] : [true]
|
@@ -848,7 +849,21 @@ EOS
|
|
848
849
|
got = nil
|
849
850
|
tnam = "Test #{id} lenient=#{lenient} exfl=#{exfl}"
|
850
851
|
begin
|
851
|
-
dg_from_import(tnam, grid)
|
852
|
+
dg = dg_from_import(tnam, grid)
|
853
|
+
|
854
|
+
# make sure export of line1 works correctly
|
855
|
+
# when dg is lenient and/or has constraint and/or
|
856
|
+
# not float
|
857
|
+
next unless lenient || constraint.present? ||
|
858
|
+
type != 'float'
|
859
|
+
|
860
|
+
# also skip grids where we included float explicitly
|
861
|
+
# because export will convert back to implicit
|
862
|
+
next if type == 'float' && exfl
|
863
|
+
|
864
|
+
dga = dg.export_array
|
865
|
+
line1 = dga.first.first.join("\t") + "\n"
|
866
|
+
expect(line1).to eq(grid.lines.first)
|
852
867
|
rescue StandardError => e
|
853
868
|
got = e.message
|
854
869
|
end
|
data/spec/support/netzke.rb
CHANGED
@@ -53,7 +53,8 @@ module Marty; module RSpec; module Netzke
|
|
53
53
|
wait_for_element do
|
54
54
|
begin
|
55
55
|
cmp = first("a[data-qtip='#{button_name}']")
|
56
|
-
cmp ||=
|
56
|
+
cmp ||= all(:xpath, './/a', text: button_name.to_s).
|
57
|
+
detect { |c| c.text == button_name.to_s }
|
57
58
|
cmp ||= find(:btn, button_name, match: :first)
|
58
59
|
cmp.click
|
59
60
|
true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2019-
|
17
|
+
date: 2019-07-05 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: pg
|
@@ -230,6 +230,7 @@ files:
|
|
230
230
|
- ".rspec"
|
231
231
|
- ".rubocop.yml"
|
232
232
|
- ".rubocop_todo.yml"
|
233
|
+
- ".ssh-docker/.keep"
|
233
234
|
- ".travis.yml"
|
234
235
|
- Dockerfile.dummy
|
235
236
|
- Gemfile
|
@@ -256,6 +257,7 @@ files:
|
|
256
257
|
- app/components/marty/auth_app/client/auth_app.js
|
257
258
|
- app/components/marty/base_rule_view.rb
|
258
259
|
- app/components/marty/config_view.rb
|
260
|
+
- app/components/marty/data_grid_user_view.rb
|
259
261
|
- app/components/marty/data_grid_view.rb
|
260
262
|
- app/components/marty/data_grid_view/client/data_grid_edit.js
|
261
263
|
- app/components/marty/delorean_rule_view.rb
|
@@ -394,6 +396,7 @@ files:
|
|
394
396
|
- db/migrate/105_create_marty_grid_index_booleans.rb
|
395
397
|
- db/migrate/106_make_grid_indexes_nullable.rb
|
396
398
|
- db/migrate/107_add_data_grid_constraint.rb
|
399
|
+
- db/migrate/108_add_data_grid_perms.rb
|
397
400
|
- db/migrate/200_create_marty_event_operation_enum.rb
|
398
401
|
- db/migrate/201_create_marty_events.rb
|
399
402
|
- db/migrate/202_add_completion_status_to_event.rb
|
@@ -462,6 +465,7 @@ files:
|
|
462
465
|
- marty.gemspec
|
463
466
|
- other/marty/api/base.rb
|
464
467
|
- other/marty/diagnostic/aws/ec2_instance.rb
|
468
|
+
- other/marty/diagnostic/aws/error.rb
|
465
469
|
- other/marty/diagnostic/base.rb
|
466
470
|
- other/marty/diagnostic/collection.rb
|
467
471
|
- other/marty/diagnostic/connections.rb
|