marty 5.1.4 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 76a0d4a1329fc8a257a905e327c3245dde1e638a
4
- data.tar.gz: e918f2b2349a35da28cfdd7e01c0c6710cc5190c
2
+ SHA256:
3
+ metadata.gz: c09276b6e27aad355d8f9b512b7bdd753f62a19fc669757f6835337c20554f7f
4
+ data.tar.gz: 91626928a7caa158cc81628978b00d5b1a8b0266c24960c5d6164e06ef0815aa
5
5
  SHA512:
6
- metadata.gz: ca56ed8fdeb18d1951a6ceeefb7ae3d7b63b7292ac7a577d628153384c333693888feb2669c9ec6ad1074a680ab89a6db9a8212e3540462ee79d6410f937deae
7
- data.tar.gz: 36157384d4e25c764cbe1277380603da2e3ef359a07220f2e1572ad7b3a3f2a29810e0917d8a3a9af4e9795e6b3dc45280a523fd0a436f0278b6cd744f44ca03
6
+ metadata.gz: b5901679d961b8484cdf274566d1f0bf8781364b0ce83a542bf1aee859f72ba6d95e8de2f71430ae5ceb86888c301e45fa0b29444ff770e60a3aed58ba64456c
7
+ data.tar.gz: 1b849061d5d1293f43e6949820426004f73fe3e6f385e72a18e33bc0bc8d52446dd854069944e77cc0dcf55549b3308930b7c0058aef5e63c36e55a22ca7fdef
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ group :default do
9
9
  gem 'daemons'
10
10
  gem 'delayed_job_active_record'
11
11
  gem 'pg'
12
- gem 'rails'
12
+ gem 'rails', '>= 5.2.3', '< 6.0.0'
13
13
  end
14
14
 
15
15
  group :default, :cmit do
@@ -17,7 +17,7 @@ module Marty
17
17
  end
18
18
 
19
19
  client_class do |c|
20
- c.do_edit_in_form = l(<<~JS)
20
+ fn = l(<<~JS)
21
21
  function(record) {
22
22
  var sel = this.getSelectionModel().getSelection()[0];
23
23
  var record_id = sel && sel.getId();
@@ -25,6 +25,10 @@ module Marty
25
25
  this.server.editGrid({record_id: record_id});
26
26
  }
27
27
  JS
28
+
29
+ # inherited perms don't work right, set both fns to the fancy grid edit
30
+ c.do_edit_in_form = fn
31
+ c.do_view_in_form = fn
28
32
  end
29
33
 
30
34
  def default_bbar
@@ -159,4 +159,22 @@
159
159
  clearFilters: function() {
160
160
  this.filters.clearFilters();
161
161
  },
162
+
163
+ netzkeGridSelectedDefaultAction: function(endpoint, confirmation) {
164
+ var selected = this.getSelectionModel().getSelection().map((r) => r.id)
165
+
166
+ if (confirmation) {
167
+ Ext.Msg.confirm(
168
+ confirmation,
169
+ Ext.String.format('Are you sure?'),
170
+ (btn, value, cfg) => {
171
+ if (btn == "yes") {
172
+ this.server[endpoint](selected, () => { this.unmask() })
173
+ }
174
+ }
175
+ );
176
+ } else {
177
+ this.server[endpoint](selected, () => { this.unmask() })
178
+ }
179
+ }
162
180
  }
@@ -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/schedule_jobs_logs'
7
8
  require 'marty/data_grid_user_view'
8
9
  require 'marty/event_view'
9
10
  require 'marty/import_type_view'
@@ -116,6 +117,7 @@ class Marty::MainAuthApp < Marty::AuthApp
116
117
  :bg_stop,
117
118
  :bg_restart,
118
119
  :schedule_jobs_dashboard,
120
+ :schedule_jobs_logs,
119
121
  ]
120
122
  },
121
123
  ]
@@ -295,6 +297,14 @@ class Marty::MainAuthApp < Marty::AuthApp
295
297
  a.handler = :netzke_load_component_by_action
296
298
  end
297
299
 
300
+ action :schedule_jobs_logs do |a|
301
+ a.text = "Schedule Job's Logs"
302
+ a.tooltip = "Show Scheduled Job's logs"
303
+ a.icon_cls = 'fa fa-cog glyph'
304
+ a.disabled = !self.class.has_perm?(:admin)
305
+ a.handler = :netzke_load_component_by_action
306
+ end
307
+
298
308
  action :log_view do |a|
299
309
  a.text = 'View Log'
300
310
  a.tooltip = 'View Log'
@@ -394,6 +404,8 @@ class Marty::MainAuthApp < Marty::AuthApp
394
404
 
395
405
  component :schedule_jobs_dashboard
396
406
 
407
+ component :schedule_jobs_logs
408
+
397
409
  component :config_view
398
410
 
399
411
  component :data_grid_view
@@ -0,0 +1,85 @@
1
+ class Marty::ScheduleJobsLogs < Marty::Grid
2
+ ACCESSIBLE_BY = [:admin]
3
+
4
+ has_marty_permissions(
5
+ read: ACCESSIBLE_BY,
6
+ create: ACCESSIBLE_BY,
7
+ update: ACCESSIBLE_BY,
8
+ delete: ACCESSIBLE_BY,
9
+ destroy: ACCESSIBLE_BY,
10
+ destroy_all: ACCESSIBLE_BY,
11
+ ignore: ACCESSIBLE_BY,
12
+ edit_window__edit_form__submit: ACCESSIBLE_BY,
13
+ add_window__add_form__submit: ACCESSIBLE_BY
14
+ )
15
+
16
+ def configure(c)
17
+ super
18
+
19
+ c.title ||= I18n.t('schedule_jobs_dashboard_view_title', default: "Scheduled Job's Logs")
20
+ c.model = 'Marty::BackgroundJob::Log'
21
+ c.paging = :buffered
22
+ c.editing = :in_form
23
+ c.multi_select = true
24
+
25
+ c.attributes = [
26
+ :job_class,
27
+ :status,
28
+ :error,
29
+ :created_at
30
+ ]
31
+
32
+ c.store_config.merge!(sorters: [{ property: :id, direction: 'DESC' }])
33
+ end
34
+
35
+ def default_context_menu
36
+ []
37
+ end
38
+
39
+ def default_bbar
40
+ [:delete, :destroy_all, :ignore]
41
+ end
42
+
43
+ attribute :job_class do |c|
44
+ c.width = 400
45
+ c.read_only = true
46
+ end
47
+
48
+ attribute :status do |c|
49
+ c.read_only = true
50
+ end
51
+
52
+ attribute :error do |c|
53
+ c.width = 800
54
+ c.read_only = true
55
+ c.getter = ->(record) { record.error.to_json }
56
+ end
57
+
58
+ action :destroy_all do |a|
59
+ a.text = 'Delete all'
60
+ a.tooltip = 'Delete all logs'
61
+ a.icon_cls = 'fa fa-trash glyph'
62
+ end
63
+
64
+ action :ignore do |a|
65
+ a.text = 'Ignore in diag'
66
+ a.tooltip = 'Ignore in diag'
67
+ a.icon_cls = 'fa fa-trash glyph'
68
+ end
69
+
70
+ endpoint :destroy_all do
71
+ Marty::BackgroundJob::Log.delete_all
72
+ client.reload
73
+ end
74
+
75
+ endpoint :ignore do |ids|
76
+ Marty::BackgroundJob::Log.
77
+ where(id: ids).
78
+ where(status: :failure).
79
+ each { |record| record.update(status: :failure_ignore) }
80
+
81
+ client.reload
82
+ end
83
+ end
84
+
85
+ ScheduleJobsLogs = Marty::ScheduleJobsLogs
@@ -0,0 +1,15 @@
1
+ {
2
+ netzkeOnDestroyAll: function(params) {
3
+ Ext.Msg.confirm(
4
+ 'Delete all',
5
+ Ext.String.format('Are you sure?'),
6
+ (btn, value, cfg) => {
7
+ if (btn == "yes") {
8
+ this.mask('Deleting...');
9
+ this.server.destroyAll(() => { this.unmask()});
10
+ }
11
+ });
12
+ },
13
+
14
+ netzkeOnIgnore: function(_) { return this.netzkeGridSelectedDefaultAction('ignore') }
15
+ }
@@ -1,4 +1,34 @@
1
1
  class Marty::CronJob < ActiveJob::Base
2
+ around_perform do |_job, block|
3
+ begin
4
+ block.call
5
+ log_success
6
+ rescue StandardError => e
7
+ log_failure(e)
8
+ raise e
9
+ end
10
+ end
11
+
12
+ def log_failure(exception)
13
+ error = {
14
+ message: exception.message,
15
+ backtrace: exception.backtrace
16
+ }
17
+
18
+ ::Marty::BackgroundJob::Log.create!(
19
+ job_class: self.class.name,
20
+ status: :failure,
21
+ error: error
22
+ )
23
+ end
24
+
25
+ def log_success
26
+ ::Marty::BackgroundJob::Log.create!(
27
+ job_class: self.class.name,
28
+ status: :success
29
+ )
30
+ end
31
+
2
32
  class << self
3
33
  def schedule
4
34
  return reschedule if scheduled?
@@ -0,0 +1,12 @@
1
+ module Marty
2
+ module BackgroundJob
3
+ class Log < Marty::Base
4
+ self.table_name = 'marty_background_job_logs'
5
+
6
+ validates :job_class, :status, presence: true
7
+
8
+ ALL_STATUSES = %w[success failure failure_ignore].freeze
9
+ enum status: ALL_STATUSES.zip(ALL_STATUSES).to_h
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class CreateMartyDelayedJobLogs < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :marty_background_job_logs do |t|
4
+ t.string :job_class, null: false
5
+ t.string :status, null: false
6
+ t.jsonb :error
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :marty_background_job_logs, :job_class
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Marty
2
- VERSION = '5.1.4'
2
+ VERSION = '5.2.0'
3
3
  end
@@ -20,8 +20,9 @@ module Marty::Diagnostic::Database
20
20
  end
21
21
 
22
22
  def self.db_schema
23
- current = ActiveRecord::Migration.current_version
23
+ current = ActiveRecord::Migrator.current_version
24
24
  raise "Migration is needed.\nCurrent Version: #{current}" if
25
+ Rails.version >= '5.2.0' &&
25
26
  ActiveRecord::Base.connection.migration_context.needs_migration?
26
27
 
27
28
  current.to_s
@@ -0,0 +1,25 @@
1
+ module Marty::Diagnostic; class ScheduledJobs < Base
2
+ self.aggregatable = false
3
+
4
+ diagnostic_fn do
5
+ logs = ::Marty::BackgroundJob::Log.
6
+ order(job_class: :asc, status: :desc, id: :desc).
7
+ select('DISTINCT ON(job_class, status) *').
8
+ where.not(status: :failure_ignore).
9
+ first(1000)
10
+
11
+ failed_total = ::Marty::BackgroundJob::Log.where(status: :failure).count
12
+
13
+ result = logs.each_with_object({}) do |log, hash|
14
+ message = "Status: #{log.status}, last_run: #{log.created_at}"
15
+ message = "#{message}, error: #{log.error}" if log.failure?
16
+ hash[log.job_class] = log.success? ? message : error(message)
17
+ end
18
+
19
+ result['Failures total'] = 0
20
+ result['Failures total'] = error(failed_total) if failed_total != 0
21
+
22
+ result
23
+ end
24
+ end
25
+ end
@@ -1 +1 @@
1
- spec/dummy/public/images/../extjs/icons/
1
+ ../extjs/icons/
@@ -1 +1 @@
1
- spec/dummy/spec/features/../../../features/javascripts/
1
+ ../../../features/javascripts/
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Schedule Jobs Logs', js: true do
4
+ before do
5
+ populate_test_users
6
+ end
7
+
8
+ context 'as dev' do
9
+ before do
10
+ log_in_as('dev1')
11
+ wait_for_ajax
12
+ press('System')
13
+ press('Background Jobs')
14
+ press("Schedule Job's Logs")
15
+ wait_for_ajax
16
+ end
17
+
18
+ it 'access denied' do
19
+ expect(page).to_not have_content "Schedule Job's Logs"
20
+ end
21
+ end
22
+
23
+ context 'as admin' do
24
+ let(:grid_view) { netzke_find('schedule_jobs_logs') }
25
+
26
+ let!(:create_logs) do
27
+ Marty::BackgroundJob::Log.create!(
28
+ job_class: 'TestJob2',
29
+ status: :success,
30
+ created_at: 3.minutes.ago
31
+ )
32
+
33
+ Marty::BackgroundJob::Log.create!(
34
+ job_class: 'TestJob2',
35
+ status: :failure,
36
+ error: { message: 'Test error message', backtrace: '' },
37
+ created_at: 2.minutes.ago
38
+ )
39
+
40
+ Marty::BackgroundJob::Log.create!(
41
+ job_class: 'Another Test Job',
42
+ status: :success,
43
+ created_at: 1.minute.ago
44
+ )
45
+ end
46
+
47
+ before do
48
+ log_in_as('admin1')
49
+ wait_for_ajax
50
+ press('System')
51
+ press('Background Jobs')
52
+ press("Schedule Job's Logs")
53
+
54
+ wait_for_ajax
55
+
56
+ expect(page).to have_content "Scheduled Job's Logs"
57
+ end
58
+
59
+ it 'shows logs' do
60
+ class_names = grid_view.get_col_vals('job_class', 3, 0)
61
+
62
+ expect(class_names.uniq).to eq ['Another Test Job', 'TestJob2']
63
+
64
+ statuses = grid_view.get_col_vals('status', 3, 0)
65
+ expect(statuses).to eq ['success', 'failure', 'success']
66
+ end
67
+
68
+ it 'deletes log' do
69
+ find('.x-grid-item', text: 'Another Test Job').click
70
+ press 'Delete'
71
+ press 'Yes'
72
+
73
+ wait_for_ajax
74
+
75
+ class_names = grid_view.get_col_vals('job_class', 2, 0)
76
+ expect(class_names.uniq).to eq ['TestJob2']
77
+ end
78
+
79
+ it 'deletes all logs' do
80
+ press 'Delete all'
81
+ press 'Yes'
82
+
83
+ wait_for_ajax
84
+
85
+ expect(grid_view.row_count).to eq 0
86
+ expect(Marty::BackgroundJob::Log.count).to eq 0
87
+ end
88
+
89
+ it 'marks as ignored in diags' do
90
+ expect(Marty::BackgroundJob::Log.failure_ignore.count).to eq 0
91
+ find('.x-grid-item', text: 'Test error').click
92
+ press 'Ignore in diag'
93
+ press 'Yes'
94
+
95
+ wait_for_ajax
96
+
97
+ statuses = grid_view.get_col_vals('status', 3, 0)
98
+ expect(statuses).to eq ['success', 'failure_ignore', 'success']
99
+ expect(Marty::BackgroundJob::Log.failure_ignore.count).to eq 1
100
+ end
101
+ end
102
+ end
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: 5.1.4
4
+ version: 5.2.0
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-08-13 00:00:00.000000000 Z
17
+ date: 2019-09-09 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: aws-sigv4
@@ -293,6 +293,8 @@ files:
293
293
  - app/components/marty/reporting/client/reporting.js
294
294
  - app/components/marty/schedule_jobs_dashboard.rb
295
295
  - app/components/marty/schedule_jobs_dashboard/client/schedule_jobs_dashboard.js
296
+ - app/components/marty/schedule_jobs_logs.rb
297
+ - app/components/marty/schedule_jobs_logs/client/schedule_jobs_logs.js
296
298
  - app/components/marty/script_form.rb
297
299
  - app/components/marty/script_form/client/script_form.js
298
300
  - app/components/marty/script_grid.rb
@@ -319,6 +321,7 @@ files:
319
321
  - app/models/marty/api_auth.rb
320
322
  - app/models/marty/api_config.rb
321
323
  - app/models/marty/background_job.rb
324
+ - app/models/marty/background_job/log.rb
322
325
  - app/models/marty/background_job/schedule.rb
323
326
  - app/models/marty/base.rb
324
327
  - app/models/marty/base_rule.rb
@@ -412,6 +415,7 @@ files:
412
415
  - db/migrate/507_migrate_marty_roles_to_enum.rb
413
416
  - db/migrate/508_add_not_to_data_grids_tables.rb
414
417
  - db/migrate/509_update_dg_plpgsql_v1_fns.rb
418
+ - db/migrate/511_create_marty_delayed_job_logs.rb
415
419
  - db/seeds.rb
416
420
  - db/sql/lookup_grid_distinct_v1.sql
417
421
  - db/sql/query_grid_dir_v1.sql
@@ -476,6 +480,7 @@ files:
476
480
  - other/marty/diagnostic/packer.rb
477
481
  - other/marty/diagnostic/reporter.rb
478
482
  - other/marty/diagnostic/request.rb
483
+ - other/marty/diagnostic/scheduled_jobs.rb
479
484
  - other/marty/diagnostic/version.rb
480
485
  - script/rails
481
486
  - spec/controllers/application_controller_spec.rb
@@ -1600,6 +1605,7 @@ files:
1600
1605
  - spec/features/reporting_spec.rb
1601
1606
  - spec/features/rule_spec.rb
1602
1607
  - spec/features/schedule_jobs_dashboard_spec.rb
1608
+ - spec/features/schedule_jobs_logs_spec.rb
1603
1609
  - spec/features/scripting_spec.rb
1604
1610
  - spec/features/scripting_test_spec.rb
1605
1611
  - spec/features/user_view_spec.rb
@@ -1694,8 +1700,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1694
1700
  - !ruby/object:Gem::Version
1695
1701
  version: '0'
1696
1702
  requirements: []
1697
- rubyforge_project:
1698
- rubygems_version: 2.6.14
1703
+ rubygems_version: 3.0.3
1699
1704
  signing_key:
1700
1705
  specification_version: 4
1701
1706
  summary: A framework for working with versioned data