marty 8.3.1 → 8.4.1
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 +4 -4
- data/app/components/marty/background_job/delayed_jobs_grid.rb +71 -0
- data/app/components/marty/background_job/schedule_jobs_dashboard.rb +53 -0
- data/app/components/marty/background_job/schedule_jobs_grid.rb +136 -0
- data/app/components/marty/{schedule_jobs_grid → background_job/schedule_jobs_grid}/client/schedule_jobs_grid.js +0 -0
- data/app/components/marty/background_job/schedule_jobs_logs.rb +87 -0
- data/app/components/marty/{schedule_jobs_logs → background_job/schedule_jobs_logs}/client/schedule_jobs_logs.js +0 -0
- data/app/components/marty/main_auth_app.rb +25 -7
- data/lib/marty/data_conversion.rb +1 -1
- data/lib/marty/version.rb +1 -1
- data/spec/features/delayed_jobs_grid_spec.rb +80 -0
- data/spec/lib/data_conversion_spec.rb +54 -0
- metadata +10 -7
- data/app/components/marty/schedule_jobs_dashboard.rb +0 -52
- data/app/components/marty/schedule_jobs_grid.rb +0 -118
- data/app/components/marty/schedule_jobs_logs.rb +0 -85
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d2b7a71540fdd0a796cc8bd62725ddfa80231af28875eff79b5cbf1e6b8d65a
|
4
|
+
data.tar.gz: de508c108b52dc8b89d9d873030173594952a5c48ee507c68438f2e01a21d136
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efbcc2b834193e2525809e494d6e12936d75606b03f7c2fb9970008eb3adac30bb4a193c9bd64323691db0fdd983401aba0e73907df16f839bfb4675551094af
|
7
|
+
data.tar.gz: 1c2834966a5b98f4177a14a297eed967b88a94b7f56c6c3597445e6dcd25ab96cad08465bcbf31f4675a76cc2d977f0a198efae2b15f47e64f771159ae2dfdf6
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
class DelayedJobsGrid < Marty::Grid
|
4
|
+
ACCESSIBLE_BY = [:admin]
|
5
|
+
|
6
|
+
has_marty_permissions(
|
7
|
+
read: ACCESSIBLE_BY,
|
8
|
+
create: nil,
|
9
|
+
update: nil,
|
10
|
+
delete: nil,
|
11
|
+
destroy: ACCESSIBLE_BY,
|
12
|
+
job_run: ACCESSIBLE_BY,
|
13
|
+
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
14
|
+
add_window__add_form__submit: ACCESSIBLE_BY
|
15
|
+
)
|
16
|
+
|
17
|
+
def configure(c)
|
18
|
+
super
|
19
|
+
|
20
|
+
c.title ||= I18n.t(
|
21
|
+
'schedule_jobs_dashboard_view_title',
|
22
|
+
default: 'Delayed Jobs Dashboard'
|
23
|
+
)
|
24
|
+
|
25
|
+
c.model = 'Delayed::Job'
|
26
|
+
c.paging = :buffered
|
27
|
+
c.editing = :in_form
|
28
|
+
c.multi_select = false
|
29
|
+
|
30
|
+
c.attributes = [
|
31
|
+
:id,
|
32
|
+
:handler,
|
33
|
+
:run_at,
|
34
|
+
:locked_at,
|
35
|
+
:locked_by,
|
36
|
+
:created_at,
|
37
|
+
:cron,
|
38
|
+
:last_error
|
39
|
+
]
|
40
|
+
|
41
|
+
c.store_config.merge!(
|
42
|
+
sorters: [
|
43
|
+
{ property: :locked_at, direction: 'DESC' },
|
44
|
+
{ property: :run_at, direction: 'DESC' }
|
45
|
+
])
|
46
|
+
|
47
|
+
# c.scope = lambda do |r|
|
48
|
+
# r.order('locked_at DESC NULLS LAST')
|
49
|
+
# end
|
50
|
+
end
|
51
|
+
|
52
|
+
attribute :locked_at do |c|
|
53
|
+
c.sorting_scope = lambda do |relation, dir|
|
54
|
+
relation.order("locked_at #{dir} NULLS LAST")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_context_menu
|
59
|
+
[]
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_bbar
|
63
|
+
[]
|
64
|
+
end
|
65
|
+
|
66
|
+
attribute :cron do |c|
|
67
|
+
c.width = 400
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'marty/background_job/schedule_jobs_grid'
|
2
|
+
|
3
|
+
module Marty
|
4
|
+
module BackgroundJob
|
5
|
+
class ScheduleJobsDashboard < Marty::Form
|
6
|
+
include Marty::Extras::Layout
|
7
|
+
|
8
|
+
def configure(c)
|
9
|
+
super
|
10
|
+
c.items = [
|
11
|
+
:schedule_jobs_grid,
|
12
|
+
:schedule_jobs_warnings
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
def prepare_warnings
|
17
|
+
djs = ::Marty::BackgroundJob::FetchMissingInScheduleCronJobs.call
|
18
|
+
|
19
|
+
messages = djs.map do |dj|
|
20
|
+
handler_str = dj.handler[/job_class.*\n/]
|
21
|
+
job_class = handler_str.gsub('job_class:', '').strip
|
22
|
+
|
23
|
+
"#{job_class} with cron #{dj.cron} is present " \
|
24
|
+
'in delayed_jobs table, but is missing in the Dashboard.'
|
25
|
+
end
|
26
|
+
|
27
|
+
messages.join('<br>')
|
28
|
+
end
|
29
|
+
|
30
|
+
client_class do |c|
|
31
|
+
c.header = false
|
32
|
+
c.defaults = { body_style: 'padding:0px' }
|
33
|
+
end
|
34
|
+
|
35
|
+
component :schedule_jobs_grid do |c|
|
36
|
+
c.klass = Marty::BackgroundJob::ScheduleJobsGrid
|
37
|
+
c.region = :north
|
38
|
+
c.min_height = 500
|
39
|
+
end
|
40
|
+
|
41
|
+
component :schedule_jobs_warnings do |c|
|
42
|
+
c.klass = Marty::Panel
|
43
|
+
c.title = I18n.t('jobs.schedule_dashboard.warnings')
|
44
|
+
c.html = prepare_warnings
|
45
|
+
c.min_height = 200
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_bbar
|
49
|
+
[]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
class ScheduleJobsGrid < Marty::Grid
|
4
|
+
ACCESSIBLE_BY = [:admin]
|
5
|
+
|
6
|
+
has_marty_permissions(
|
7
|
+
read: ACCESSIBLE_BY,
|
8
|
+
create: ACCESSIBLE_BY,
|
9
|
+
update: ACCESSIBLE_BY,
|
10
|
+
delete: ACCESSIBLE_BY,
|
11
|
+
destroy: ACCESSIBLE_BY,
|
12
|
+
job_run: ACCESSIBLE_BY,
|
13
|
+
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
14
|
+
add_window__add_form__submit: ACCESSIBLE_BY
|
15
|
+
)
|
16
|
+
|
17
|
+
def configure(c)
|
18
|
+
super
|
19
|
+
|
20
|
+
c.title ||= I18n.t(
|
21
|
+
'schedule_jobs_dashboard_view_title',
|
22
|
+
default: 'Schedule Jobs Dashboard'
|
23
|
+
)
|
24
|
+
|
25
|
+
c.model = 'Marty::BackgroundJob::Schedule'
|
26
|
+
c.paging = :buffered
|
27
|
+
c.editing = :in_form
|
28
|
+
c.multi_select = false
|
29
|
+
|
30
|
+
c.attributes = [
|
31
|
+
:job_class,
|
32
|
+
:cron,
|
33
|
+
:state
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_context_menu
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_bbar
|
42
|
+
super + [:do_job_run]
|
43
|
+
end
|
44
|
+
|
45
|
+
attribute :job_class do |c|
|
46
|
+
c.width = 400
|
47
|
+
end
|
48
|
+
|
49
|
+
attribute :cron do |c|
|
50
|
+
c.width = 400
|
51
|
+
end
|
52
|
+
|
53
|
+
attribute :state do |c|
|
54
|
+
c.width = 150
|
55
|
+
editor_config = {
|
56
|
+
trigger_action: :all,
|
57
|
+
xtype: :combo,
|
58
|
+
store: Marty::BackgroundJob::Schedule::ALL_STATES,
|
59
|
+
forceSelection: true,
|
60
|
+
}
|
61
|
+
|
62
|
+
c.column_config = { editor: editor_config }
|
63
|
+
c.field_config = editor_config
|
64
|
+
end
|
65
|
+
|
66
|
+
action :do_job_run do |a|
|
67
|
+
a.text = 'Run'
|
68
|
+
a.tooltip = 'Run'
|
69
|
+
a.icon_cls = 'fa fa-play glyph'
|
70
|
+
a.disabled = true
|
71
|
+
end
|
72
|
+
|
73
|
+
endpoint :edit_window__edit_form__submit do |params|
|
74
|
+
result = super(params)
|
75
|
+
next result if result.empty?
|
76
|
+
|
77
|
+
obj_hash = result.first
|
78
|
+
|
79
|
+
Marty::BackgroundJob::UpdateSchedule.call(
|
80
|
+
id: obj_hash['id'],
|
81
|
+
job_class: obj_hash['job_class']
|
82
|
+
)
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
endpoint :add_window__add_form__submit do |params|
|
88
|
+
result = super(params)
|
89
|
+
next result if result.empty?
|
90
|
+
|
91
|
+
obj_hash = result.first
|
92
|
+
|
93
|
+
Marty::BackgroundJob::UpdateSchedule.call(
|
94
|
+
id: obj_hash['id'],
|
95
|
+
job_class: obj_hash['job_class']
|
96
|
+
)
|
97
|
+
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
endpoint :multiedit_window__multiedit_form__submit do |_params|
|
102
|
+
client.netzke_notify 'Multiediting is disabled for cron schedules'
|
103
|
+
end
|
104
|
+
|
105
|
+
endpoint :destroy do |params|
|
106
|
+
res = params.each_with_object({}) do |id, hash|
|
107
|
+
job_class = model.find_by(id: id)&.job_class
|
108
|
+
result = super([id])
|
109
|
+
|
110
|
+
# Do nothing If it wasn't destroyed
|
111
|
+
next hash.merge(result) unless result[id.to_i] == 'ok'
|
112
|
+
|
113
|
+
Marty::BackgroundJob::UpdateSchedule.call(
|
114
|
+
id: id,
|
115
|
+
job_class: job_class
|
116
|
+
)
|
117
|
+
|
118
|
+
hash.merge(result)
|
119
|
+
end
|
120
|
+
|
121
|
+
res
|
122
|
+
end
|
123
|
+
|
124
|
+
endpoint :job_run do
|
125
|
+
begin
|
126
|
+
s = Marty::BackgroundJob::Schedule.find(client_config['selected'])
|
127
|
+
klass = s.job_class
|
128
|
+
klass.constantize.new.perform
|
129
|
+
rescue StandardError => e
|
130
|
+
next client.netzke_notify(e.message)
|
131
|
+
end
|
132
|
+
client.netzke_notify("#{klass.demodulize} ran successfully.")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
File without changes
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
class ScheduleJobsLogs < Marty::Grid
|
4
|
+
ACCESSIBLE_BY = [:admin]
|
5
|
+
|
6
|
+
has_marty_permissions(
|
7
|
+
read: ACCESSIBLE_BY,
|
8
|
+
create: ACCESSIBLE_BY,
|
9
|
+
update: ACCESSIBLE_BY,
|
10
|
+
delete: ACCESSIBLE_BY,
|
11
|
+
destroy: ACCESSIBLE_BY,
|
12
|
+
destroy_all: ACCESSIBLE_BY,
|
13
|
+
ignore: ACCESSIBLE_BY,
|
14
|
+
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
15
|
+
add_window__add_form__submit: ACCESSIBLE_BY
|
16
|
+
)
|
17
|
+
|
18
|
+
def configure(c)
|
19
|
+
super
|
20
|
+
|
21
|
+
c.title ||= I18n.t('schedule_jobs_dashboard_view_title', default: "Scheduled Job's Logs")
|
22
|
+
c.model = 'Marty::BackgroundJob::Log'
|
23
|
+
c.paging = :buffered
|
24
|
+
c.editing = :in_form
|
25
|
+
c.multi_select = true
|
26
|
+
|
27
|
+
c.attributes = [
|
28
|
+
:job_class,
|
29
|
+
:status,
|
30
|
+
:error,
|
31
|
+
:created_at
|
32
|
+
]
|
33
|
+
|
34
|
+
c.store_config.merge!(sorters: [{ property: :id, direction: 'DESC' }])
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_context_menu
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_bbar
|
42
|
+
[:delete, :destroy_all, :ignore]
|
43
|
+
end
|
44
|
+
|
45
|
+
attribute :job_class do |c|
|
46
|
+
c.width = 400
|
47
|
+
c.read_only = true
|
48
|
+
end
|
49
|
+
|
50
|
+
attribute :status do |c|
|
51
|
+
c.read_only = true
|
52
|
+
end
|
53
|
+
|
54
|
+
attribute :error do |c|
|
55
|
+
c.width = 800
|
56
|
+
c.read_only = true
|
57
|
+
c.getter = ->(record) { record.error.to_json }
|
58
|
+
end
|
59
|
+
|
60
|
+
action :destroy_all do |a|
|
61
|
+
a.text = 'Delete all'
|
62
|
+
a.tooltip = 'Delete all logs'
|
63
|
+
a.icon_cls = 'fa fa-trash glyph'
|
64
|
+
end
|
65
|
+
|
66
|
+
action :ignore do |a|
|
67
|
+
a.text = 'Ignore in diag'
|
68
|
+
a.tooltip = 'Ignore in diag'
|
69
|
+
a.icon_cls = 'fa fa-trash glyph'
|
70
|
+
end
|
71
|
+
|
72
|
+
endpoint :destroy_all do
|
73
|
+
Marty::BackgroundJob::Log.delete_all
|
74
|
+
client.reload
|
75
|
+
end
|
76
|
+
|
77
|
+
endpoint :ignore do |ids|
|
78
|
+
Marty::BackgroundJob::Log.
|
79
|
+
where(id: ids).
|
80
|
+
where(status: :failure).
|
81
|
+
each { |record| record.update(status: :failure_ignore) }
|
82
|
+
|
83
|
+
client.reload
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
File without changes
|
@@ -1,20 +1,21 @@
|
|
1
1
|
require 'marty/api_auth_view'
|
2
2
|
require 'marty/api_config_view'
|
3
3
|
require 'marty/api_log_view'
|
4
|
+
require 'marty/background_job/delayed_jobs_grid'
|
5
|
+
require 'marty/background_job/schedule_jobs_dashboard'
|
6
|
+
require 'marty/background_job/schedule_jobs_logs'
|
4
7
|
require 'marty/config_view'
|
5
8
|
require 'marty/data_grid_view'
|
6
|
-
require 'marty/schedule_jobs_dashboard'
|
7
|
-
require 'marty/schedule_jobs_logs'
|
8
9
|
require 'marty/data_grid_user_view'
|
9
10
|
require 'marty/import_type_view'
|
10
11
|
require 'marty/new_posting_window'
|
12
|
+
require 'marty/notifications/config_view'
|
13
|
+
require 'marty/notifications/deliveries_view'
|
11
14
|
require 'marty/posting_window'
|
12
15
|
require 'marty/promise_view'
|
13
16
|
require 'marty/reporting'
|
14
17
|
require 'marty/scripting'
|
15
18
|
require 'marty/user_view'
|
16
|
-
require 'marty/notifications/config_view'
|
17
|
-
require 'marty/notifications/deliveries_view'
|
18
19
|
|
19
20
|
class Marty::MainAuthApp < Marty::AuthApp
|
20
21
|
extend ::Marty::Permissions
|
@@ -116,6 +117,7 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
116
117
|
:bg_status,
|
117
118
|
:bg_stop,
|
118
119
|
:bg_restart,
|
120
|
+
:delayed_jobs_grid,
|
119
121
|
:schedule_jobs_dashboard,
|
120
122
|
:schedule_jobs_logs,
|
121
123
|
]
|
@@ -298,6 +300,14 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
298
300
|
a.disabled = !self.class.has_perm?(:admin)
|
299
301
|
end
|
300
302
|
|
303
|
+
action :delayed_jobs_grid do |a|
|
304
|
+
a.text = 'Delayed Jobs Dashboard'
|
305
|
+
a.tooltip = 'Show running delayed jobs'
|
306
|
+
a.icon_cls = 'fa fa-clock glyph'
|
307
|
+
a.disabled = !self.class.has_perm?(:admin)
|
308
|
+
a.handler = :netzke_load_component_by_action
|
309
|
+
end
|
310
|
+
|
301
311
|
action :schedule_jobs_dashboard do |a|
|
302
312
|
a.text = 'Schedule Jobs Dashboard'
|
303
313
|
a.tooltip = 'Edit Delayed Jobs Cron schedules'
|
@@ -438,9 +448,9 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
438
448
|
|
439
449
|
component :api_config_view
|
440
450
|
|
441
|
-
component :
|
442
|
-
|
443
|
-
|
451
|
+
component :delayed_jobs_grid do |c|
|
452
|
+
c.klass = ::Marty::BackgroundJob::DelayedJobsGrid
|
453
|
+
end
|
444
454
|
|
445
455
|
component :config_view
|
446
456
|
|
@@ -472,6 +482,14 @@ class Marty::MainAuthApp < Marty::AuthApp
|
|
472
482
|
|
473
483
|
component :reporting
|
474
484
|
|
485
|
+
component :schedule_jobs_dashboard do |c|
|
486
|
+
c.klass = ::Marty::BackgroundJob::ScheduleJobsDashboard
|
487
|
+
end
|
488
|
+
|
489
|
+
component :schedule_jobs_logs do |c|
|
490
|
+
c.klass = ::Marty::BackgroundJob::ScheduleJobsLogs
|
491
|
+
end
|
492
|
+
|
475
493
|
component :scripting do |c|
|
476
494
|
c.allow_edit = self.class.has_scripting_perm?
|
477
495
|
end
|
@@ -56,7 +56,7 @@ class Marty::DataConversion
|
|
56
56
|
# Dates are kept as float in Google spreadsheets. Need to
|
57
57
|
# convert them to dates.
|
58
58
|
begin
|
59
|
-
FLOAT_PAT.match?(v) ? EXCEL_START_DATE + v.to_f :
|
59
|
+
FLOAT_PAT.match?(v.to_s) ? EXCEL_START_DATE + v.to_f :
|
60
60
|
Mcfly.is_infinity(v) ? 'infinity' : v.to_date
|
61
61
|
rescue StandardError => e
|
62
62
|
raise "date conversion failed for #{v.inspect}}"
|
data/lib/marty/version.rb
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Delayed Jobs Dashboard', js: true do
|
4
|
+
before do
|
5
|
+
Delayed::Job.delete_all
|
6
|
+
populate_test_users
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'as dev' do
|
10
|
+
before do
|
11
|
+
log_in_as('dev1')
|
12
|
+
wait_for_ajax
|
13
|
+
press('System')
|
14
|
+
press('Background Jobs')
|
15
|
+
press('Schedule Jobs Dashboard')
|
16
|
+
wait_for_ajax
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'access denied' do
|
20
|
+
expect(page).to_not have_content 'Schedule Jobs Dashboard'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'as admin' do
|
25
|
+
let(:jobs_view) { netzke_find('delayed_jobs_grid') }
|
26
|
+
|
27
|
+
let!(:schedule) do
|
28
|
+
['TestJob', 'Test2Job', 'TestFailingJob'].each do |klass_name|
|
29
|
+
Marty::BackgroundJob::Schedule.create(
|
30
|
+
job_class: klass_name,
|
31
|
+
cron: '0 0 * * *',
|
32
|
+
state: 'on'
|
33
|
+
).tap do |job|
|
34
|
+
Marty::BackgroundJob::UpdateSchedule.call(
|
35
|
+
id: job.id,
|
36
|
+
job_class: job.job_class
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:time1) { 10.hours.ago }
|
43
|
+
|
44
|
+
let(:time2) { 20.hours.ago }
|
45
|
+
|
46
|
+
before do
|
47
|
+
@djs = Delayed::Job.all
|
48
|
+
@djs.first.update!(locked_at: time1)
|
49
|
+
@djs.last.update!(locked_at: time2)
|
50
|
+
|
51
|
+
log_in_as('admin1')
|
52
|
+
wait_for_ajax
|
53
|
+
press('System')
|
54
|
+
press('Background Jobs')
|
55
|
+
press('Delayed Jobs Dashboard')
|
56
|
+
|
57
|
+
wait_for_ajax
|
58
|
+
|
59
|
+
expect(page).to have_content 'Delayed Jobs Dashboard'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'shows delayed jobs' do
|
63
|
+
expect(jobs_view.row_count).to eq @djs.size
|
64
|
+
expect(jobs_view.row_count).to eq 3
|
65
|
+
locked_at = jobs_view.get_col_vals('locked_at', 3, 0, false).map do |str|
|
66
|
+
next unless str
|
67
|
+
|
68
|
+
Time.zone.parse(str).to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
expect(locked_at).to eq(
|
72
|
+
[
|
73
|
+
time1.to_s,
|
74
|
+
time2.to_s,
|
75
|
+
nil
|
76
|
+
]
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Marty
|
4
|
+
describe DataConversion do
|
5
|
+
describe '#convert' do
|
6
|
+
describe 'date' do
|
7
|
+
let(:date) { 1.day.ago.to_date }
|
8
|
+
|
9
|
+
it 'converts float strings to date' do
|
10
|
+
res = described_class.convert('40000.0', :date)
|
11
|
+
expect(res).to eq Date.new(2009, 7, 6)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'converts date to date' do
|
15
|
+
res = described_class.convert(date, :date)
|
16
|
+
expect(res).to eq date
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'converts infinity' do
|
20
|
+
['Infinity', 'infinity', ::Float::INFINITY].each do |value|
|
21
|
+
res = described_class.convert(value, :date)
|
22
|
+
expect(res).to eq 'infinity'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'raises error if the value is not valid' do
|
27
|
+
expect { described_class.convert(true, :date) }.
|
28
|
+
to raise_error(/date conversion failed for true/)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'boolean' do
|
33
|
+
it 'converts true' do
|
34
|
+
['true', '1', 'y', 't'].each do |value|
|
35
|
+
res = described_class.convert(value, :boolean)
|
36
|
+
expect(res).to eq true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'converts false' do
|
41
|
+
['false', '0', 'n', 'f'].each do |value|
|
42
|
+
res = described_class.convert(value, :boolean)
|
43
|
+
expect(res).to eq false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'raises error if the value is not valid' do
|
48
|
+
expect { described_class.convert(1.day.ago, :boolean) }.
|
49
|
+
to raise_error(/unknown boolean/)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
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: 8.
|
4
|
+
version: 8.4.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-12-
|
17
|
+
date: 2019-12-05 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: actioncable
|
@@ -310,6 +310,12 @@ files:
|
|
310
310
|
- app/components/marty/api_log_view.rb
|
311
311
|
- app/components/marty/auth_app.rb
|
312
312
|
- app/components/marty/auth_app/client/auth_app.js
|
313
|
+
- app/components/marty/background_job/delayed_jobs_grid.rb
|
314
|
+
- app/components/marty/background_job/schedule_jobs_dashboard.rb
|
315
|
+
- app/components/marty/background_job/schedule_jobs_grid.rb
|
316
|
+
- app/components/marty/background_job/schedule_jobs_grid/client/schedule_jobs_grid.js
|
317
|
+
- app/components/marty/background_job/schedule_jobs_logs.rb
|
318
|
+
- app/components/marty/background_job/schedule_jobs_logs/client/schedule_jobs_logs.js
|
313
319
|
- app/components/marty/base_rule_view.rb
|
314
320
|
- app/components/marty/base_rule_view/client/base_rule_view.js
|
315
321
|
- app/components/marty/config_view.rb
|
@@ -356,11 +362,6 @@ files:
|
|
356
362
|
- app/components/marty/report_select/client/report_select.js
|
357
363
|
- app/components/marty/reporting.rb
|
358
364
|
- app/components/marty/reporting/client/reporting.js
|
359
|
-
- app/components/marty/schedule_jobs_dashboard.rb
|
360
|
-
- app/components/marty/schedule_jobs_grid.rb
|
361
|
-
- app/components/marty/schedule_jobs_grid/client/schedule_jobs_grid.js
|
362
|
-
- app/components/marty/schedule_jobs_logs.rb
|
363
|
-
- app/components/marty/schedule_jobs_logs/client/schedule_jobs_logs.js
|
364
365
|
- app/components/marty/script_form.rb
|
365
366
|
- app/components/marty/script_form/client/script_form.js
|
366
367
|
- app/components/marty/script_grid.rb
|
@@ -1695,6 +1696,7 @@ files:
|
|
1695
1696
|
- spec/features/data_blame_report_spec.rb
|
1696
1697
|
- spec/features/data_grid_spec.rb
|
1697
1698
|
- spec/features/data_import_spec.rb
|
1699
|
+
- spec/features/delayed_jobs_grid_spec.rb
|
1698
1700
|
- spec/features/endpoint_access.rb
|
1699
1701
|
- spec/features/enum_spec.rb
|
1700
1702
|
- spec/features/enum_values_report_spec.rb
|
@@ -1737,6 +1739,7 @@ files:
|
|
1737
1739
|
- spec/job_helper.rb
|
1738
1740
|
- spec/jobs/cron_job_spec.rb
|
1739
1741
|
- spec/lib/data_blame_spec.rb
|
1742
|
+
- spec/lib/data_conversion_spec.rb
|
1740
1743
|
- spec/lib/data_exporter_spec.rb
|
1741
1744
|
- spec/lib/data_importer_spec.rb
|
1742
1745
|
- spec/lib/delorean_query_spec.rb
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'marty/schedule_jobs_grid'
|
2
|
-
|
3
|
-
class Marty::ScheduleJobsDashboard < Marty::Form
|
4
|
-
include Marty::Extras::Layout
|
5
|
-
|
6
|
-
def configure(c)
|
7
|
-
super
|
8
|
-
c.items = [
|
9
|
-
:schedule_jobs_grid,
|
10
|
-
:schedule_jobs_warnings
|
11
|
-
]
|
12
|
-
end
|
13
|
-
|
14
|
-
def prepare_warnings
|
15
|
-
djs = ::Marty::BackgroundJob::FetchMissingInScheduleCronJobs.call
|
16
|
-
|
17
|
-
messages = djs.map do |dj|
|
18
|
-
handler_str = dj.handler[/job_class.*\n/]
|
19
|
-
job_class = handler_str.gsub('job_class:', '').strip
|
20
|
-
|
21
|
-
"#{job_class} with cron #{dj.cron} is present in delayed_jobs table, " \
|
22
|
-
'but is missing in the Dashboard.'
|
23
|
-
end
|
24
|
-
|
25
|
-
messages.join('<br>')
|
26
|
-
end
|
27
|
-
|
28
|
-
client_class do |c|
|
29
|
-
c.header = false
|
30
|
-
# c.layout = :border
|
31
|
-
c.defaults = { body_style: 'padding:0px' }
|
32
|
-
end
|
33
|
-
|
34
|
-
component :schedule_jobs_grid do |c|
|
35
|
-
c.klass = Marty::ScheduleJobsGrid
|
36
|
-
c.region = :north
|
37
|
-
c.min_height = 500
|
38
|
-
end
|
39
|
-
|
40
|
-
component :schedule_jobs_warnings do |c|
|
41
|
-
c.klass = Marty::Panel
|
42
|
-
c.title = I18n.t('jobs.schedule_dashboard.warnings')
|
43
|
-
c.html = prepare_warnings
|
44
|
-
c.min_height = 200
|
45
|
-
end
|
46
|
-
|
47
|
-
def default_bbar
|
48
|
-
[]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
ScheduleJobsDashboard = Marty::ScheduleJobsDashboard
|
@@ -1,118 +0,0 @@
|
|
1
|
-
class Marty::ScheduleJobsGrid < 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
|
-
job_run: ACCESSIBLE_BY,
|
11
|
-
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
12
|
-
add_window__add_form__submit: ACCESSIBLE_BY
|
13
|
-
)
|
14
|
-
|
15
|
-
def configure(c)
|
16
|
-
super
|
17
|
-
|
18
|
-
c.title ||= I18n.t('schedule_jobs_dashboard_view_title', default: 'Schedule Jobs Dashboard')
|
19
|
-
c.model = 'Marty::BackgroundJob::Schedule'
|
20
|
-
c.paging = :buffered
|
21
|
-
c.editing = :in_form
|
22
|
-
c.multi_select = false
|
23
|
-
|
24
|
-
c.attributes = [
|
25
|
-
:job_class,
|
26
|
-
:cron,
|
27
|
-
:state
|
28
|
-
]
|
29
|
-
end
|
30
|
-
|
31
|
-
def default_context_menu
|
32
|
-
[]
|
33
|
-
end
|
34
|
-
|
35
|
-
def default_bbar
|
36
|
-
super + [:do_job_run]
|
37
|
-
end
|
38
|
-
|
39
|
-
attribute :job_class do |c|
|
40
|
-
c.width = 400
|
41
|
-
end
|
42
|
-
|
43
|
-
attribute :cron do |c|
|
44
|
-
c.width = 400
|
45
|
-
end
|
46
|
-
|
47
|
-
attribute :state do |c|
|
48
|
-
c.width = 150
|
49
|
-
editor_config = {
|
50
|
-
trigger_action: :all,
|
51
|
-
xtype: :combo,
|
52
|
-
store: Marty::BackgroundJob::Schedule::ALL_STATES,
|
53
|
-
forceSelection: true,
|
54
|
-
}
|
55
|
-
|
56
|
-
c.column_config = { editor: editor_config }
|
57
|
-
c.field_config = editor_config
|
58
|
-
end
|
59
|
-
|
60
|
-
action :do_job_run do |a|
|
61
|
-
a.text = 'Run'
|
62
|
-
a.tooltip = 'Run'
|
63
|
-
a.icon_cls = 'fa fa-play glyph'
|
64
|
-
a.disabled = true
|
65
|
-
end
|
66
|
-
|
67
|
-
endpoint :edit_window__edit_form__submit do |params|
|
68
|
-
result = super(params)
|
69
|
-
next result if result.empty?
|
70
|
-
|
71
|
-
obj_hash = result.first
|
72
|
-
Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
|
73
|
-
|
74
|
-
result
|
75
|
-
end
|
76
|
-
|
77
|
-
endpoint :add_window__add_form__submit do |params|
|
78
|
-
result = super(params)
|
79
|
-
next result if result.empty?
|
80
|
-
|
81
|
-
obj_hash = result.first
|
82
|
-
Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
|
83
|
-
|
84
|
-
result
|
85
|
-
end
|
86
|
-
|
87
|
-
endpoint :multiedit_window__multiedit_form__submit do |_params|
|
88
|
-
client.netzke_notify 'Multiediting is disabled for cron schedules'
|
89
|
-
end
|
90
|
-
|
91
|
-
endpoint :destroy do |params|
|
92
|
-
res = params.each_with_object({}) do |id, hash|
|
93
|
-
job_class = model.find_by(id: id)&.job_class
|
94
|
-
result = super([id])
|
95
|
-
|
96
|
-
# Do nothing If it wasn't destroyed
|
97
|
-
next hash.merge(result) unless result[id.to_i] == 'ok'
|
98
|
-
|
99
|
-
Marty::BackgroundJob::UpdateSchedule.call(id: id, job_class: job_class)
|
100
|
-
hash.merge(result)
|
101
|
-
end
|
102
|
-
|
103
|
-
res
|
104
|
-
end
|
105
|
-
|
106
|
-
endpoint :job_run do
|
107
|
-
begin
|
108
|
-
s = Marty::BackgroundJob::Schedule.find(client_config['selected'])
|
109
|
-
klass = s.job_class
|
110
|
-
klass.constantize.new.perform
|
111
|
-
rescue StandardError => e
|
112
|
-
next client.netzke_notify(e.message)
|
113
|
-
end
|
114
|
-
client.netzke_notify("#{klass.demodulize} ran successfully.")
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
ScheduleJobsGrid = Marty::ScheduleJobsGrid
|
@@ -1,85 +0,0 @@
|
|
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
|