marty 5.1.4 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
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