marty 2.5.2 → 2.5.4
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 +5 -5
- data/.gitignore +4 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +11 -589
- data/Gemfile +9 -9
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -3
- data/app/components/marty/api_auth_view.rb +3 -3
- data/app/components/marty/api_config_view.rb +8 -8
- data/app/components/marty/api_log_view.rb +16 -20
- data/app/components/marty/auth_app.rb +6 -6
- data/app/components/marty/base_rule_view.rb +27 -19
- data/app/components/marty/config_view.rb +12 -9
- data/app/components/marty/data_grid_view.rb +26 -26
- data/app/components/marty/delorean_rule_view.rb +0 -1
- data/app/components/marty/event_view.rb +27 -27
- data/app/components/marty/extras/layout.rb +26 -26
- data/app/components/marty/extras/misc.rb +2 -2
- data/app/components/marty/grid.rb +13 -13
- data/app/components/marty/grid_append_only.rb +0 -1
- data/app/components/marty/import_type_view.rb +13 -13
- data/app/components/marty/import_view.rb +17 -16
- data/app/components/marty/log_view.rb +16 -14
- data/app/components/marty/main_auth_app.rb +59 -59
- data/app/components/marty/main_auth_app/client/main_auth_app.js +3 -3
- data/app/components/marty/mcfly_grid_panel.rb +10 -10
- data/app/components/marty/new_posting_form.rb +11 -11
- data/app/components/marty/new_posting_window.rb +0 -1
- data/app/components/marty/posting_grid.rb +12 -13
- data/app/components/marty/promise_view.rb +6 -6
- data/app/components/marty/report_form.rb +50 -53
- data/app/components/marty/report_select.rb +27 -27
- data/app/components/marty/reporting.rb +4 -4
- data/app/components/marty/script_form.rb +40 -42
- data/app/components/marty/script_grid.rb +24 -24
- data/app/components/marty/script_tester.rb +40 -42
- data/app/components/marty/scripting.rb +25 -27
- data/app/components/marty/simple_app.rb +24 -9
- data/app/components/marty/tag_grid.rb +12 -13
- data/app/components/marty/user_view.rb +35 -35
- data/app/controllers/marty/application_controller.rb +3 -4
- data/app/controllers/marty/components_controller.rb +1 -1
- data/app/controllers/marty/delayed_job_controller.rb +1 -0
- data/app/controllers/marty/diagnostic/controller.rb +4 -6
- data/app/controllers/marty/job_controller.rb +6 -6
- data/app/controllers/marty/report_controller.rb +11 -11
- data/app/controllers/marty/rpc_controller.rb +15 -16
- data/app/helpers/marty/script_set.rb +4 -4
- data/app/models/marty/api_auth.rb +4 -5
- data/app/models/marty/api_config.rb +1 -1
- data/app/models/marty/base.rb +9 -8
- data/app/models/marty/base_rule.rb +18 -13
- data/app/models/marty/config.rb +4 -5
- data/app/models/marty/data_grid.rb +157 -181
- data/app/models/marty/delorean_rule.rb +63 -62
- data/app/models/marty/enum.rb +1 -1
- data/app/models/marty/event.rb +56 -59
- data/app/models/marty/helper.rb +38 -6
- data/app/models/marty/import_type.rb +6 -6
- data/app/models/marty/log.rb +3 -2
- data/app/models/marty/name_validator.rb +3 -2
- data/app/models/marty/pg_enum.rb +3 -4
- data/app/models/marty/posting.rb +20 -24
- data/app/models/marty/promise.rb +28 -30
- data/app/models/marty/script.rb +30 -28
- data/app/models/marty/tag.rb +8 -8
- data/app/models/marty/token.rb +2 -2
- data/app/models/marty/user.rb +24 -23
- data/app/models/marty/vw_promise.rb +10 -11
- data/config/routes.rb +2 -2
- data/delorean/blame_report.dl +268 -0
- data/{spec/dummy/delorean/fields.dl → delorean/marty_fields.dl} +8 -0
- data/delorean/table_report.dl +34 -0
- data/docker-compose.dummy.yml +2 -3
- data/lib/marty/aws/base.rb +8 -8
- data/lib/marty/aws/request.rb +4 -4
- data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -0
- data/lib/marty/content_handler.rb +25 -25
- data/lib/marty/data_change.rb +49 -71
- data/lib/marty/data_conversion.rb +20 -28
- data/lib/marty/data_exporter.rb +25 -28
- data/lib/marty/data_importer.rb +25 -27
- data/lib/marty/engine.rb +1 -2
- data/lib/marty/json_schema.rb +22 -24
- data/lib/marty/logger.rb +6 -9
- data/lib/marty/mcfly_model.rb +20 -24
- data/lib/marty/migrations.rb +37 -35
- data/lib/marty/monkey.rb +33 -33
- data/lib/marty/permissions.rb +18 -18
- data/lib/marty/promise_job.rb +17 -17
- data/lib/marty/promise_proxy.rb +6 -6
- data/lib/marty/relation.rb +6 -7
- data/lib/marty/rpc_call.rb +13 -12
- data/lib/marty/rule_script_set.rb +32 -28
- data/lib/marty/schema_helper.rb +37 -51
- data/lib/marty/util.rb +25 -24
- data/lib/marty/version.rb +1 -1
- data/lib/marty/xl.rb +121 -115
- data/make-dummy.mk +3 -0
- data/marty.gemspec +21 -21
- data/other/marty/api/base.rb +34 -35
- data/other/marty/diagnostic/aws/ec2_instance.rb +8 -8
- data/other/marty/diagnostic/base.rb +13 -14
- data/other/marty/diagnostic/collection.rb +2 -1
- data/other/marty/diagnostic/connections.rb +8 -6
- data/other/marty/diagnostic/database.rb +1 -0
- data/other/marty/diagnostic/delayed_job_version.rb +7 -9
- data/other/marty/diagnostic/delayed_job_worker_total_count.rb +1 -1
- data/other/marty/diagnostic/delayed_job_workers.rb +1 -1
- data/other/marty/diagnostic/environment_variables.rb +17 -15
- data/other/marty/diagnostic/fatal.rb +1 -1
- data/other/marty/diagnostic/node.rb +5 -9
- data/other/marty/diagnostic/nodes.rb +7 -5
- data/other/marty/diagnostic/packer.rb +7 -7
- data/other/marty/diagnostic/reporter.rb +24 -27
- data/other/marty/diagnostic/version.rb +3 -5
- data/script/rails +2 -1
- data/spec/controllers/application_controller_spec.rb +6 -6
- data/spec/controllers/delayed_job_controller_spec.rb +4 -4
- data/spec/controllers/diagnostic/controller_spec.rb +59 -60
- data/spec/controllers/job_controller_spec.rb +68 -69
- data/spec/controllers/rpc_controller_spec.rb +353 -359
- data/spec/controllers/rpc_import_spec.rb +15 -16
- data/spec/dummy/delorean/blame_report.dl +110 -15
- data/spec/dummy/delorean/data_report.dl +4 -4
- data/spec/dummy/delorean/marty_fields.dl +63 -0
- data/spec/dummy/delorean/table_report.dl +34 -0
- data/spec/features/auth_app_spec.rb +1 -2
- data/spec/features/data_import_spec.rb +2 -3
- data/spec/features/enum_spec.rb +42 -46
- data/spec/features/jobs_dashboard_spec.rb +14 -8
- data/spec/features/log_view_spec.rb +40 -43
- data/spec/features/reporting_spec.rb +15 -15
- data/spec/features/rule_spec.rb +195 -190
- data/spec/features/scripting_spec.rb +17 -20
- data/spec/features/scripting_test_spec.rb +32 -33
- data/spec/features/user_view_spec.rb +15 -17
- data/spec/job_helper.rb +11 -11
- data/spec/lib/data_blame_spec.rb +82 -0
- data/spec/lib/data_exporter_spec.rb +31 -32
- data/spec/lib/data_importer_spec.rb +382 -395
- data/spec/lib/delorean_query_spec.rb +117 -119
- data/spec/lib/json_schema_spec.rb +382 -392
- data/spec/lib/logger_spec.rb +23 -24
- data/spec/lib/mcfly_model_spec.rb +112 -109
- data/spec/lib/migrations_spec.rb +10 -10
- data/spec/lib/struct_compare_spec.rb +6 -6
- data/spec/lib/table_report_spec.rb +90 -0
- data/spec/lib/xl_spec.rb +63 -65
- data/spec/lib/xl_styles_spec.rb +16 -19
- data/spec/models/api_auth_spec.rb +30 -30
- data/spec/models/config_spec.rb +32 -32
- data/spec/models/data_grid_spec.rb +642 -655
- data/spec/models/event_spec.rb +96 -88
- data/spec/models/import_type_spec.rb +20 -20
- data/spec/models/posting_spec.rb +35 -35
- data/spec/models/promise_spec.rb +5 -5
- data/spec/models/rule_spec.rb +280 -269
- data/spec/models/script_spec.rb +27 -18
- data/spec/models/user_spec.rb +9 -9
- data/spec/other/diagnostic/base_spec.rb +20 -19
- data/spec/other/diagnostic/collection_spec.rb +6 -5
- data/spec/other/diagnostic/delayed_job_version_spec.rb +1 -1
- data/spec/other/diagnostic/delayed_job_workers_spec.rb +8 -8
- data/spec/other/diagnostic/reporter_spec.rb +31 -33
- data/spec/spec_helper.rb +5 -5
- data/spec/support/chromedriver.rb +3 -5
- data/spec/support/components/netzke_combobox.rb +1 -1
- data/spec/support/components/netzke_grid.rb +17 -17
- data/spec/support/custom_matchers.rb +2 -2
- data/spec/support/download_helper.rb +1 -1
- data/spec/support/helper.rb +1 -2
- data/spec/support/netzke.rb +31 -31
- data/spec/support/performance_helper.rb +8 -8
- data/spec/support/post_run_logger.rb +1 -2
- data/spec/support/setup.rb +1 -4
- data/spec/support/shared_connection.rb +2 -2
- data/spec/support/structure_compare.rb +21 -22
- data/spec/support/suite.rb +1 -2
- data/spec/support/users.rb +5 -6
- metadata +32 -26
data/app/models/marty/tag.rb
CHANGED
|
@@ -4,10 +4,10 @@ class Marty::Tag < Marty::Base
|
|
|
4
4
|
mcfly_validates_uniqueness_of :name
|
|
5
5
|
validates_presence_of :name, :comment
|
|
6
6
|
|
|
7
|
-
belongs_to :user, class_name:
|
|
7
|
+
belongs_to :user, class_name: 'Marty::User'
|
|
8
8
|
|
|
9
9
|
def self.get_struct_attrs
|
|
10
|
-
self.struct_attrs ||= super + [
|
|
10
|
+
self.struct_attrs ||= super + ['id', 'created_dt']
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def self.make_name(dt)
|
|
@@ -23,7 +23,7 @@ class Marty::Tag < Marty::Base
|
|
|
23
23
|
|
|
24
24
|
before_validation :set_tag_name
|
|
25
25
|
def set_tag_name
|
|
26
|
-
self.name = self.class.make_name(
|
|
26
|
+
self.name = self.class.make_name(created_dt)
|
|
27
27
|
true
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -60,21 +60,21 @@ class Marty::Tag < Marty::Base
|
|
|
60
60
|
tag = tag_id
|
|
61
61
|
end
|
|
62
62
|
raise "bad tag identifier #{tag_id.inspect}" unless tag.is_a?(Marty::Tag)
|
|
63
|
+
|
|
63
64
|
tag
|
|
64
65
|
end
|
|
65
66
|
|
|
66
|
-
cached_delorean_fn :lookup, sig: 1 do
|
|
67
|
-
|
|
68
|
-
t = self.find_by_name(name).select(get_struct_attrs)
|
|
67
|
+
cached_delorean_fn :lookup, sig: 1 do |name|
|
|
68
|
+
t = find_by_name(name).select(get_struct_attrs)
|
|
69
69
|
t && t.attributes
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def self.get_latest1
|
|
73
|
-
order(
|
|
73
|
+
order('created_dt DESC').find_by("created_dt <> 'infinity'")
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def self.find_match(dt)
|
|
77
|
-
order(
|
|
77
|
+
order('created_dt DESC').find_by('created_dt <= ?', dt)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
# Performance hack for script sets -- FIXME: making find_mtach
|
data/app/models/marty/token.rb
CHANGED
|
@@ -15,7 +15,8 @@ class Marty::Token < Marty::Base
|
|
|
15
15
|
# return Time.now > self.created_on + @@validity_time
|
|
16
16
|
# end
|
|
17
17
|
|
|
18
|
-
private
|
|
18
|
+
private
|
|
19
|
+
|
|
19
20
|
def self.generate_token_value
|
|
20
21
|
SecureRandom.hex(20)
|
|
21
22
|
end
|
|
@@ -26,5 +27,4 @@ private
|
|
|
26
27
|
Token.delete_all(['user_id = ?', user.id])
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
|
-
|
|
30
30
|
end
|
data/app/models/marty/user.rb
CHANGED
|
@@ -58,9 +58,9 @@ class Marty::User < Marty::Base
|
|
|
58
58
|
|
|
59
59
|
auth_source = cf.auth_source.to_s
|
|
60
60
|
|
|
61
|
-
if auth_source ==
|
|
61
|
+
if auth_source == 'local'
|
|
62
62
|
ok = password == cf.local_password
|
|
63
|
-
elsif auth_source ==
|
|
63
|
+
elsif auth_source == 'ldap'
|
|
64
64
|
# IMPORTANT NOTE: if server allows anonymous LDAP access, empty
|
|
65
65
|
# passwords will succeed! i.e. if a valid user with empty
|
|
66
66
|
# password is sent in, ldap.bind will return OK.
|
|
@@ -71,7 +71,7 @@ class Marty::User < Marty::Base
|
|
|
71
71
|
encryption: cf.encryption,
|
|
72
72
|
auth: {
|
|
73
73
|
method: :simple,
|
|
74
|
-
username: cf.domain +
|
|
74
|
+
username: cf.domain + '\\' + login,
|
|
75
75
|
password: password,
|
|
76
76
|
})
|
|
77
77
|
ok = ldap.bind
|
|
@@ -90,12 +90,13 @@ class Marty::User < Marty::Base
|
|
|
90
90
|
Mcfly.whodunnit
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
def self.has_role(role)
|
|
94
|
+
mr = Mcfly.whodunnit.roles rescue []
|
|
95
|
+
mr.any? { |attr| attr.name == role }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
97
99
|
|
|
98
|
-
private
|
|
99
100
|
def verify_changes
|
|
100
101
|
# If current users role is only user_manager, restrict following
|
|
101
102
|
# 1 - Do not allow user to edit own record
|
|
@@ -105,37 +106,37 @@ private
|
|
|
105
106
|
Rails.configuration.marty.system_account.to_s)
|
|
106
107
|
system_id = system_user.id if system_user
|
|
107
108
|
|
|
108
|
-
if
|
|
109
|
-
roles.each {|r| roles.delete r unless r.name ==
|
|
110
|
-
errors.add :base,
|
|
111
|
-
|
|
112
|
-
elsif
|
|
109
|
+
if id == Mcfly.whodunnit.id
|
|
110
|
+
roles.each { |r| roles.delete r unless r.name == 'user_manager' }
|
|
111
|
+
errors.add :base, 'User Managers cannot edit '\
|
|
112
|
+
'or add additional roles to their own accounts'
|
|
113
|
+
elsif id == system_id
|
|
113
114
|
errors.add :base,
|
|
114
|
-
|
|
115
|
+
'User Managers cannot edit the application system account'
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
|
|
118
|
-
errors.add :base,
|
|
119
|
-
|
|
120
|
-
!
|
|
119
|
+
errors.add :base, 'The application system account cannot be deactivated' if
|
|
120
|
+
login == Rails.configuration.marty.system_account.to_s &&
|
|
121
|
+
!active
|
|
121
122
|
|
|
122
123
|
errors.blank?
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
def user_manager_only
|
|
126
|
-
Marty::User.has_role(
|
|
127
|
+
Marty::User.has_role('user_manager') && !Marty::User.has_role('admin')
|
|
127
128
|
end
|
|
128
129
|
|
|
129
130
|
def destroy_user
|
|
130
|
-
errors.add :base,
|
|
131
|
-
|
|
131
|
+
errors.add :base, 'You cannot delete your own account' if
|
|
132
|
+
login == Mcfly.whodunnit.login
|
|
132
133
|
|
|
133
|
-
errors.add :base,
|
|
134
|
-
|
|
134
|
+
errors.add :base, 'You cannot delete the system account' if
|
|
135
|
+
login == Rails.configuration.marty.system_account.to_s
|
|
135
136
|
# Default to disallowing any deletions for now
|
|
136
137
|
|
|
137
138
|
errors.add :base,
|
|
138
|
-
|
|
139
|
+
"Users cannot be deleted - set 'Active' to false to disable the account"
|
|
139
140
|
|
|
140
141
|
throw :abort unless errors.blank?
|
|
141
142
|
end
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
class Marty::VwPromise < Marty::Base
|
|
2
|
-
|
|
3
2
|
has_many :children,
|
|
4
3
|
foreign_key: 'parent_id',
|
|
5
|
-
class_name:
|
|
4
|
+
class_name: 'Marty::VwPromise',
|
|
6
5
|
dependent: :destroy
|
|
7
6
|
|
|
8
|
-
belongs_to :parent, class_name:
|
|
9
|
-
belongs_to :user, class_name:
|
|
7
|
+
belongs_to :parent, class_name: 'Marty::VwPromise'
|
|
8
|
+
belongs_to :user, class_name: 'Marty::User'
|
|
10
9
|
|
|
11
10
|
self.table_name = 'marty_vw_promises'
|
|
12
11
|
self.primary_key = 'id'
|
|
@@ -54,19 +53,19 @@ class Marty::VwPromise < Marty::Base
|
|
|
54
53
|
|
|
55
54
|
# Support UI live search -- FIXME: hacky to have UI scoping here
|
|
56
55
|
scope :live_search, lambda { |search_text|
|
|
57
|
-
return if !search_text || search_text.strip.
|
|
56
|
+
return if !search_text || search_text.strip.empty?
|
|
58
57
|
|
|
59
58
|
# Searches user login/firstname/lastname
|
|
60
59
|
query = [
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
'marty_users.login ILIKE ?',
|
|
61
|
+
'marty_users.firstname ILIKE ?',
|
|
62
|
+
'marty_users.lastname ILIKE ?',
|
|
63
|
+
'marty_roles.name ILIKE ?',
|
|
64
|
+
].join(' OR ')
|
|
66
65
|
|
|
67
66
|
st = "%#{search_text}%"
|
|
68
67
|
# Convert "Role Name" or "Role name" to "role_name" (underscore is key)
|
|
69
68
|
st2 = "%#{search_text.titleize.gsub(/\s/, '').underscore}%"
|
|
70
|
-
joins(
|
|
69
|
+
joins(:user => :roles).where(query, st, st, st, st2).distinct
|
|
71
70
|
}
|
|
72
71
|
end
|
data/config/routes.rb
CHANGED
|
@@ -3,8 +3,8 @@ Rails.application.routes.draw do
|
|
|
3
3
|
end
|
|
4
4
|
|
|
5
5
|
Marty::Engine.routes.draw do
|
|
6
|
-
match via: [:get, :post],
|
|
7
|
-
match via: [:get, :post],
|
|
6
|
+
match via: [:get, :post], 'rpc/evaluate(.:format)' => 'rpc', as: :rpc
|
|
7
|
+
match via: [:get, :post], 'report(.:format)' => 'report#index', as: :report
|
|
8
8
|
get 'job/download' => 'job', as: :job
|
|
9
9
|
post 'delayed_job/trigger' => 'delayed_job#trigger', as: :trigger_delayed_job
|
|
10
10
|
get 'diag', to: 'diagnostic/#op'
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import MartyFields
|
|
2
|
+
import Styles
|
|
3
|
+
|
|
4
|
+
PostingField2: MartyFields::PostingField2
|
|
5
|
+
store = [ ["NOW", "NOW"] ] + [ [ lp.name, lp.name + ' (' + lp.comment + ')']
|
|
6
|
+
for lp in Marty::Posting.get_latest_by_type(
|
|
7
|
+
20, ['BASE', 'INTRA', 'CLOSE'])]
|
|
8
|
+
|
|
9
|
+
StyleRow:
|
|
10
|
+
profile =?
|
|
11
|
+
obj = profile["obj"]
|
|
12
|
+
status = profile["status"]
|
|
13
|
+
attrs = profile["attrs"]
|
|
14
|
+
user_name = Marty::DataChange.user_name(obj.user_id)
|
|
15
|
+
delete = profile["deleted"]
|
|
16
|
+
create = status == "new"
|
|
17
|
+
|
|
18
|
+
o_user_name = if delete then Marty::DataChange.user_name(obj.o_user_id)
|
|
19
|
+
else ""
|
|
20
|
+
o_dt = if delete then obj.obsoleted_dt.to_s else ""
|
|
21
|
+
del_style = if delete then Styles::Style.bg_redish else {}
|
|
22
|
+
mod_style = Styles::Style.bg_tan
|
|
23
|
+
new_style = if create then Styles::Style.bg_lightgreen else {}
|
|
24
|
+
|
|
25
|
+
b_style = Styles::Style.calibri + new_style
|
|
26
|
+
b_c_style = b_style + mod_style
|
|
27
|
+
m_style = b_style + Styles::Style.bg_lightgray + del_style
|
|
28
|
+
m_d_style = m_style + Styles::Style.datetime
|
|
29
|
+
|
|
30
|
+
row = [
|
|
31
|
+
obj.group_id,
|
|
32
|
+
obj.created_dt.to_s,
|
|
33
|
+
user_name,
|
|
34
|
+
o_dt,
|
|
35
|
+
o_user_name,
|
|
36
|
+
] + [ a.value for a in attrs]
|
|
37
|
+
|
|
38
|
+
row_styles = [
|
|
39
|
+
m_style,
|
|
40
|
+
m_d_style,
|
|
41
|
+
m_style,
|
|
42
|
+
m_d_style,
|
|
43
|
+
m_style,
|
|
44
|
+
] + [
|
|
45
|
+
(if a.changed then b_c_style else b_style)
|
|
46
|
+
for a in attrs
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
s_row = ["row", row, {"style": row_styles}]
|
|
50
|
+
|
|
51
|
+
StyleGroup:
|
|
52
|
+
group =?
|
|
53
|
+
rows = [
|
|
54
|
+
StyleRow(profile = profile).s_row
|
|
55
|
+
for profile in group
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
ModelRows:
|
|
59
|
+
klass =?
|
|
60
|
+
t1 =?
|
|
61
|
+
t2 =?
|
|
62
|
+
ids =?
|
|
63
|
+
|
|
64
|
+
groups = Marty::DataChange.changes(t1, t2, klass, ids)
|
|
65
|
+
|
|
66
|
+
headers = ["Group ID", "Created", "By", "Deleted", "By"] +
|
|
67
|
+
Marty::DataChange.class_headers(klass)
|
|
68
|
+
|
|
69
|
+
width = headers.length
|
|
70
|
+
border = [
|
|
71
|
+
"border",
|
|
72
|
+
[0, {"off": 1}, width, {"off": 1}],
|
|
73
|
+
Styles::Style.border_thin,
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
row_groups = [
|
|
77
|
+
StyleGroup(group = x[1]).rows + [border]
|
|
78
|
+
for x in groups
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
s_style = {"style": [Styles::Style.s_hdr] * width}
|
|
82
|
+
s_headers = ["row", headers, s_style]
|
|
83
|
+
rows = [s_headers] + row_groups.flatten(1)
|
|
84
|
+
count = row_groups.length
|
|
85
|
+
ws = if count > 0 then [klass, rows] else nil
|
|
86
|
+
|
|
87
|
+
OptionalIDsField: MartyFields::TextField
|
|
88
|
+
field_label = "Group IDs (optional)"
|
|
89
|
+
name = "restrict_to_ids"
|
|
90
|
+
|
|
91
|
+
DataBlameReport:
|
|
92
|
+
title = "Data Blame Report"
|
|
93
|
+
|
|
94
|
+
pt_name1 =?
|
|
95
|
+
posting1 =? Marty::Posting.lookup(pt_name1)
|
|
96
|
+
t1 = posting1.created_dt
|
|
97
|
+
|
|
98
|
+
pt_name2 =?
|
|
99
|
+
posting2 =? Marty::Posting.lookup(pt_name2)
|
|
100
|
+
t2 = posting2.created_dt
|
|
101
|
+
|
|
102
|
+
class_list =? false
|
|
103
|
+
restrict_to_ids =? nil
|
|
104
|
+
|
|
105
|
+
form = [
|
|
106
|
+
MartyFields::PostingField1,
|
|
107
|
+
PostingField2,
|
|
108
|
+
MartyFields::ClassListField,
|
|
109
|
+
OptionalIDsField
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
ts = if Marty::Helper.infinity_dt(t1)
|
|
113
|
+
then [t2, t1]
|
|
114
|
+
else if Marty::Helper.infinity_dt(t2)
|
|
115
|
+
then [t1, t2]
|
|
116
|
+
else [t1, t2].sort
|
|
117
|
+
|
|
118
|
+
sanitized = if class_list
|
|
119
|
+
then Marty::DataChange.sanitize_classes(class_list)
|
|
120
|
+
else Marty::DataChange.class_list
|
|
121
|
+
|
|
122
|
+
ids = if restrict_to_ids
|
|
123
|
+
then [ idstr.to_i for idstr in restrict_to_ids.split(',') ]
|
|
124
|
+
else nil
|
|
125
|
+
|
|
126
|
+
ids_check = if ids && ids.length > 0 && sanitized.length > 1
|
|
127
|
+
then ERR("Can't specify Group IDs if more than one class selected")
|
|
128
|
+
else true
|
|
129
|
+
|
|
130
|
+
result = ids_check && [
|
|
131
|
+
ModelRows(t1 = ts[0], t2 = ts[1], klass = klass,
|
|
132
|
+
ids = ids).ws
|
|
133
|
+
for klass in sanitized
|
|
134
|
+
].compact
|
|
135
|
+
|
|
136
|
+
format = "xlsx"
|
|
137
|
+
|
|
138
|
+
ModelSummaryRow:
|
|
139
|
+
klass =?
|
|
140
|
+
t1 =?
|
|
141
|
+
t2 =?
|
|
142
|
+
|
|
143
|
+
r = Marty::DataChange.change_summary(t1, t2, klass)
|
|
144
|
+
cr = r['created']
|
|
145
|
+
up = r['updated']
|
|
146
|
+
dl = r['deleted']
|
|
147
|
+
|
|
148
|
+
ws = if cr > 0 || up > 0 || dl > 0 then ["row", [klass, cr, up, dl]] else nil
|
|
149
|
+
|
|
150
|
+
DataBlameReportSummary:
|
|
151
|
+
title = "Summary Data Blame Report"
|
|
152
|
+
|
|
153
|
+
pt_name1 =?
|
|
154
|
+
posting1 =? Marty::Posting.lookup(pt_name1)
|
|
155
|
+
t1 = posting1.created_dt
|
|
156
|
+
|
|
157
|
+
pt_name2 =?
|
|
158
|
+
posting2 =? Marty::Posting.lookup(pt_name2)
|
|
159
|
+
t2 = posting2.created_dt
|
|
160
|
+
|
|
161
|
+
form = [
|
|
162
|
+
MartyFields::PostingField1,
|
|
163
|
+
PostingField2,
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
postings = [
|
|
167
|
+
["Posting 1", pt_name1,],
|
|
168
|
+
["Posting 2", pt_name2,],
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
hrow = [
|
|
172
|
+
"row", ["Data Table", "Created", "Updated", "Deleted",],
|
|
173
|
+
Styles::Style.m_hdr_style0,
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
ts = if Marty::Helper.infinity_dt(t1)
|
|
177
|
+
then [t2, t1]
|
|
178
|
+
else if Marty::Helper.infinity_dt(t2)
|
|
179
|
+
then [t1, t2]
|
|
180
|
+
else [t1, t2].sort
|
|
181
|
+
|
|
182
|
+
rows = [
|
|
183
|
+
ModelSummaryRow(t1 = ts[0], t2 = ts[1], klass = klass).ws
|
|
184
|
+
for klass in Marty::DataChange.class_list
|
|
185
|
+
].compact
|
|
186
|
+
|
|
187
|
+
header = [["row", r, {"style" : [Styles::Style.s_hdr]}] for r in postings]
|
|
188
|
+
result = [[title,[hrow] + rows, {"widths" : [30]}], ["Parameters", header]]
|
|
189
|
+
format = "xlsx"
|
|
190
|
+
|
|
191
|
+
DeadReferenceReport:
|
|
192
|
+
title = "Dead Reference Report"
|
|
193
|
+
|
|
194
|
+
class_list =? false
|
|
195
|
+
pt_name =?
|
|
196
|
+
posting =? Marty::Posting.lookup(pt_name)
|
|
197
|
+
|
|
198
|
+
sanitized = if class_list
|
|
199
|
+
then Marty::DataChange.sanitize_classes(class_list)
|
|
200
|
+
else Marty::DataChange.class_list
|
|
201
|
+
|
|
202
|
+
form = [
|
|
203
|
+
MartyFields::PostingField,
|
|
204
|
+
MartyFields::ClassListField,
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
result = [
|
|
208
|
+
[[[klass, attr, obj].flatten for obj in list]
|
|
209
|
+
for attr, list in Marty::DataChange.dead_refs(posting.created_dt,
|
|
210
|
+
klass)].flatten(1)
|
|
211
|
+
for klass in sanitized
|
|
212
|
+
].flatten(1)
|
|
213
|
+
|
|
214
|
+
format = "csv"
|
|
215
|
+
|
|
216
|
+
######################################################################
|
|
217
|
+
|
|
218
|
+
DataImportParam:
|
|
219
|
+
field_label = "Input Rows"
|
|
220
|
+
name = "data_import_field"
|
|
221
|
+
xtype = ":textareafield"
|
|
222
|
+
scrollable = true
|
|
223
|
+
field_style = {
|
|
224
|
+
"font_family": 'courier new',
|
|
225
|
+
"font_size": '12px',
|
|
226
|
+
}
|
|
227
|
+
height = 600
|
|
228
|
+
|
|
229
|
+
CommaSepField: MartyFields::CheckboxField
|
|
230
|
+
name = "comma_sep"
|
|
231
|
+
field_label = "Comma Separated"
|
|
232
|
+
|
|
233
|
+
DiffReport:
|
|
234
|
+
title = "Diff Report"
|
|
235
|
+
|
|
236
|
+
class_name =? false
|
|
237
|
+
data_import_field =?
|
|
238
|
+
comma_sep =? false
|
|
239
|
+
|
|
240
|
+
klass = Marty::Helper.constantize(class_name)
|
|
241
|
+
|
|
242
|
+
col_types = Marty::Helper.get_column_types(klass)
|
|
243
|
+
data = Marty::Helper.parse_csv_to_hash(
|
|
244
|
+
data_import_field, comma_sep, col_types)
|
|
245
|
+
|
|
246
|
+
diff = Marty::DataChange.diff(klass, data)
|
|
247
|
+
|
|
248
|
+
result = [{"title" : "different",
|
|
249
|
+
"format" : "csv",
|
|
250
|
+
"result" : diff["different"].flatten},
|
|
251
|
+
{"title" : "same",
|
|
252
|
+
"format" : "csv",
|
|
253
|
+
"result" : diff["same"]},
|
|
254
|
+
{"title" : "only_input",
|
|
255
|
+
"format" : "csv",
|
|
256
|
+
"result" : diff["only_input"]},
|
|
257
|
+
{"title" : "only_source",
|
|
258
|
+
"format" : "csv",
|
|
259
|
+
"result" : diff["only_source"]},
|
|
260
|
+
]
|
|
261
|
+
|
|
262
|
+
form = [
|
|
263
|
+
MartyFields::ClassField,
|
|
264
|
+
DataImportParam,
|
|
265
|
+
CommaSepField,
|
|
266
|
+
]
|
|
267
|
+
|
|
268
|
+
format = "zip"
|