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.
Files changed (181) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +7 -0
  4. data/.rubocop_todo.yml +11 -589
  5. data/Gemfile +9 -9
  6. data/Gemfile.lock +1 -1
  7. data/Rakefile +1 -3
  8. data/app/components/marty/api_auth_view.rb +3 -3
  9. data/app/components/marty/api_config_view.rb +8 -8
  10. data/app/components/marty/api_log_view.rb +16 -20
  11. data/app/components/marty/auth_app.rb +6 -6
  12. data/app/components/marty/base_rule_view.rb +27 -19
  13. data/app/components/marty/config_view.rb +12 -9
  14. data/app/components/marty/data_grid_view.rb +26 -26
  15. data/app/components/marty/delorean_rule_view.rb +0 -1
  16. data/app/components/marty/event_view.rb +27 -27
  17. data/app/components/marty/extras/layout.rb +26 -26
  18. data/app/components/marty/extras/misc.rb +2 -2
  19. data/app/components/marty/grid.rb +13 -13
  20. data/app/components/marty/grid_append_only.rb +0 -1
  21. data/app/components/marty/import_type_view.rb +13 -13
  22. data/app/components/marty/import_view.rb +17 -16
  23. data/app/components/marty/log_view.rb +16 -14
  24. data/app/components/marty/main_auth_app.rb +59 -59
  25. data/app/components/marty/main_auth_app/client/main_auth_app.js +3 -3
  26. data/app/components/marty/mcfly_grid_panel.rb +10 -10
  27. data/app/components/marty/new_posting_form.rb +11 -11
  28. data/app/components/marty/new_posting_window.rb +0 -1
  29. data/app/components/marty/posting_grid.rb +12 -13
  30. data/app/components/marty/promise_view.rb +6 -6
  31. data/app/components/marty/report_form.rb +50 -53
  32. data/app/components/marty/report_select.rb +27 -27
  33. data/app/components/marty/reporting.rb +4 -4
  34. data/app/components/marty/script_form.rb +40 -42
  35. data/app/components/marty/script_grid.rb +24 -24
  36. data/app/components/marty/script_tester.rb +40 -42
  37. data/app/components/marty/scripting.rb +25 -27
  38. data/app/components/marty/simple_app.rb +24 -9
  39. data/app/components/marty/tag_grid.rb +12 -13
  40. data/app/components/marty/user_view.rb +35 -35
  41. data/app/controllers/marty/application_controller.rb +3 -4
  42. data/app/controllers/marty/components_controller.rb +1 -1
  43. data/app/controllers/marty/delayed_job_controller.rb +1 -0
  44. data/app/controllers/marty/diagnostic/controller.rb +4 -6
  45. data/app/controllers/marty/job_controller.rb +6 -6
  46. data/app/controllers/marty/report_controller.rb +11 -11
  47. data/app/controllers/marty/rpc_controller.rb +15 -16
  48. data/app/helpers/marty/script_set.rb +4 -4
  49. data/app/models/marty/api_auth.rb +4 -5
  50. data/app/models/marty/api_config.rb +1 -1
  51. data/app/models/marty/base.rb +9 -8
  52. data/app/models/marty/base_rule.rb +18 -13
  53. data/app/models/marty/config.rb +4 -5
  54. data/app/models/marty/data_grid.rb +157 -181
  55. data/app/models/marty/delorean_rule.rb +63 -62
  56. data/app/models/marty/enum.rb +1 -1
  57. data/app/models/marty/event.rb +56 -59
  58. data/app/models/marty/helper.rb +38 -6
  59. data/app/models/marty/import_type.rb +6 -6
  60. data/app/models/marty/log.rb +3 -2
  61. data/app/models/marty/name_validator.rb +3 -2
  62. data/app/models/marty/pg_enum.rb +3 -4
  63. data/app/models/marty/posting.rb +20 -24
  64. data/app/models/marty/promise.rb +28 -30
  65. data/app/models/marty/script.rb +30 -28
  66. data/app/models/marty/tag.rb +8 -8
  67. data/app/models/marty/token.rb +2 -2
  68. data/app/models/marty/user.rb +24 -23
  69. data/app/models/marty/vw_promise.rb +10 -11
  70. data/config/routes.rb +2 -2
  71. data/delorean/blame_report.dl +268 -0
  72. data/{spec/dummy/delorean/fields.dl → delorean/marty_fields.dl} +8 -0
  73. data/delorean/table_report.dl +34 -0
  74. data/docker-compose.dummy.yml +2 -3
  75. data/lib/marty/aws/base.rb +8 -8
  76. data/lib/marty/aws/request.rb +4 -4
  77. data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -0
  78. data/lib/marty/content_handler.rb +25 -25
  79. data/lib/marty/data_change.rb +49 -71
  80. data/lib/marty/data_conversion.rb +20 -28
  81. data/lib/marty/data_exporter.rb +25 -28
  82. data/lib/marty/data_importer.rb +25 -27
  83. data/lib/marty/engine.rb +1 -2
  84. data/lib/marty/json_schema.rb +22 -24
  85. data/lib/marty/logger.rb +6 -9
  86. data/lib/marty/mcfly_model.rb +20 -24
  87. data/lib/marty/migrations.rb +37 -35
  88. data/lib/marty/monkey.rb +33 -33
  89. data/lib/marty/permissions.rb +18 -18
  90. data/lib/marty/promise_job.rb +17 -17
  91. data/lib/marty/promise_proxy.rb +6 -6
  92. data/lib/marty/relation.rb +6 -7
  93. data/lib/marty/rpc_call.rb +13 -12
  94. data/lib/marty/rule_script_set.rb +32 -28
  95. data/lib/marty/schema_helper.rb +37 -51
  96. data/lib/marty/util.rb +25 -24
  97. data/lib/marty/version.rb +1 -1
  98. data/lib/marty/xl.rb +121 -115
  99. data/make-dummy.mk +3 -0
  100. data/marty.gemspec +21 -21
  101. data/other/marty/api/base.rb +34 -35
  102. data/other/marty/diagnostic/aws/ec2_instance.rb +8 -8
  103. data/other/marty/diagnostic/base.rb +13 -14
  104. data/other/marty/diagnostic/collection.rb +2 -1
  105. data/other/marty/diagnostic/connections.rb +8 -6
  106. data/other/marty/diagnostic/database.rb +1 -0
  107. data/other/marty/diagnostic/delayed_job_version.rb +7 -9
  108. data/other/marty/diagnostic/delayed_job_worker_total_count.rb +1 -1
  109. data/other/marty/diagnostic/delayed_job_workers.rb +1 -1
  110. data/other/marty/diagnostic/environment_variables.rb +17 -15
  111. data/other/marty/diagnostic/fatal.rb +1 -1
  112. data/other/marty/diagnostic/node.rb +5 -9
  113. data/other/marty/diagnostic/nodes.rb +7 -5
  114. data/other/marty/diagnostic/packer.rb +7 -7
  115. data/other/marty/diagnostic/reporter.rb +24 -27
  116. data/other/marty/diagnostic/version.rb +3 -5
  117. data/script/rails +2 -1
  118. data/spec/controllers/application_controller_spec.rb +6 -6
  119. data/spec/controllers/delayed_job_controller_spec.rb +4 -4
  120. data/spec/controllers/diagnostic/controller_spec.rb +59 -60
  121. data/spec/controllers/job_controller_spec.rb +68 -69
  122. data/spec/controllers/rpc_controller_spec.rb +353 -359
  123. data/spec/controllers/rpc_import_spec.rb +15 -16
  124. data/spec/dummy/delorean/blame_report.dl +110 -15
  125. data/spec/dummy/delorean/data_report.dl +4 -4
  126. data/spec/dummy/delorean/marty_fields.dl +63 -0
  127. data/spec/dummy/delorean/table_report.dl +34 -0
  128. data/spec/features/auth_app_spec.rb +1 -2
  129. data/spec/features/data_import_spec.rb +2 -3
  130. data/spec/features/enum_spec.rb +42 -46
  131. data/spec/features/jobs_dashboard_spec.rb +14 -8
  132. data/spec/features/log_view_spec.rb +40 -43
  133. data/spec/features/reporting_spec.rb +15 -15
  134. data/spec/features/rule_spec.rb +195 -190
  135. data/spec/features/scripting_spec.rb +17 -20
  136. data/spec/features/scripting_test_spec.rb +32 -33
  137. data/spec/features/user_view_spec.rb +15 -17
  138. data/spec/job_helper.rb +11 -11
  139. data/spec/lib/data_blame_spec.rb +82 -0
  140. data/spec/lib/data_exporter_spec.rb +31 -32
  141. data/spec/lib/data_importer_spec.rb +382 -395
  142. data/spec/lib/delorean_query_spec.rb +117 -119
  143. data/spec/lib/json_schema_spec.rb +382 -392
  144. data/spec/lib/logger_spec.rb +23 -24
  145. data/spec/lib/mcfly_model_spec.rb +112 -109
  146. data/spec/lib/migrations_spec.rb +10 -10
  147. data/spec/lib/struct_compare_spec.rb +6 -6
  148. data/spec/lib/table_report_spec.rb +90 -0
  149. data/spec/lib/xl_spec.rb +63 -65
  150. data/spec/lib/xl_styles_spec.rb +16 -19
  151. data/spec/models/api_auth_spec.rb +30 -30
  152. data/spec/models/config_spec.rb +32 -32
  153. data/spec/models/data_grid_spec.rb +642 -655
  154. data/spec/models/event_spec.rb +96 -88
  155. data/spec/models/import_type_spec.rb +20 -20
  156. data/spec/models/posting_spec.rb +35 -35
  157. data/spec/models/promise_spec.rb +5 -5
  158. data/spec/models/rule_spec.rb +280 -269
  159. data/spec/models/script_spec.rb +27 -18
  160. data/spec/models/user_spec.rb +9 -9
  161. data/spec/other/diagnostic/base_spec.rb +20 -19
  162. data/spec/other/diagnostic/collection_spec.rb +6 -5
  163. data/spec/other/diagnostic/delayed_job_version_spec.rb +1 -1
  164. data/spec/other/diagnostic/delayed_job_workers_spec.rb +8 -8
  165. data/spec/other/diagnostic/reporter_spec.rb +31 -33
  166. data/spec/spec_helper.rb +5 -5
  167. data/spec/support/chromedriver.rb +3 -5
  168. data/spec/support/components/netzke_combobox.rb +1 -1
  169. data/spec/support/components/netzke_grid.rb +17 -17
  170. data/spec/support/custom_matchers.rb +2 -2
  171. data/spec/support/download_helper.rb +1 -1
  172. data/spec/support/helper.rb +1 -2
  173. data/spec/support/netzke.rb +31 -31
  174. data/spec/support/performance_helper.rb +8 -8
  175. data/spec/support/post_run_logger.rb +1 -2
  176. data/spec/support/setup.rb +1 -4
  177. data/spec/support/shared_connection.rb +2 -2
  178. data/spec/support/structure_compare.rb +21 -22
  179. data/spec/support/suite.rb +1 -2
  180. data/spec/support/users.rb +5 -6
  181. metadata +32 -26
@@ -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: "Marty::User"
7
+ belongs_to :user, class_name: 'Marty::User'
8
8
 
9
9
  def self.get_struct_attrs
10
- self.struct_attrs ||= super + ["id", "created_dt"]
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(self.created_dt)
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
- |name|
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("created_dt DESC").find_by("created_dt <> 'infinity'")
73
+ order('created_dt DESC').find_by("created_dt <> 'infinity'")
74
74
  end
75
75
 
76
76
  def self.find_match(dt)
77
- order("created_dt DESC").find_by("created_dt <= ?", dt)
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
@@ -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
@@ -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 == "local"
61
+ if auth_source == 'local'
62
62
  ok = password == cf.local_password
63
- elsif auth_source == "ldap"
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 + "\\" + login,
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
- def self.has_role(role)
94
- mr = Mcfly.whodunnit.roles rescue []
95
- mr.any? {|attr| attr.name == role}
96
- end
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 self.id == Mcfly.whodunnit.id
109
- roles.each {|r| roles.delete r unless r.name == "user_manager"}
110
- errors.add :base, "User Managers cannot edit "\
111
- "or add additional roles to their own accounts"
112
- elsif self.id == system_id
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
- "User Managers cannot edit the application system account"
115
+ 'User Managers cannot edit the application system account'
115
116
  end
116
117
  end
117
118
 
118
- errors.add :base, "The application system account cannot be deactivated" if
119
- self.login == Rails.configuration.marty.system_account.to_s &&
120
- !self.active
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("user_manager") && !Marty::User.has_role("admin")
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, "You cannot delete your own account" if
131
- self.login == Mcfly.whodunnit.login
131
+ errors.add :base, 'You cannot delete your own account' if
132
+ login == Mcfly.whodunnit.login
132
133
 
133
- errors.add :base, "You cannot delete the system account" if
134
- self.login == Rails.configuration.marty.system_account.to_s
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
- "Users cannot be deleted - set 'Active' to false to disable the account"
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: "Marty::VwPromise",
4
+ class_name: 'Marty::VwPromise',
6
5
  dependent: :destroy
7
6
 
8
- belongs_to :parent, class_name: "Marty::VwPromise"
9
- belongs_to :user, class_name: "Marty::User"
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.length < 1
56
+ return if !search_text || search_text.strip.empty?
58
57
 
59
58
  # Searches user login/firstname/lastname
60
59
  query = [
61
- "marty_users.login ILIKE ?",
62
- "marty_users.firstname ILIKE ?",
63
- "marty_users.lastname ILIKE ?",
64
- "marty_roles.name ILIKE ?",
65
- ].join(' OR ')
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({:user => :roles}).where(query, st, st, st, st2).distinct
69
+ joins(:user => :roles).where(query, st, st, st, st2).distinct
71
70
  }
72
71
  end
@@ -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], "rpc/evaluate(.:format)" => "rpc", as: :rpc
7
- match via: [:get, :post], "report(.:format)" => "report#index", as: :report
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"