web47core 2.0.1 → 2.2.15
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/README.md +111 -41
- data/app/controllers/status_controller.rb +8 -3
- data/app/helpers/core_form_helper.rb +6 -6
- data/app/helpers/core_helper.rb +1 -1
- data/app/helpers/core_link_helper.rb +47 -8
- data/app/helpers/core_nav_bar_helper.rb +5 -4
- data/app/helpers/core_table_helper.rb +80 -0
- data/app/helpers/model_modal_helper.rb +3 -3
- data/app/views/common/_create_actions.html.haml +12 -0
- data/app/views/common/_update_actions.html.haml +10 -0
- data/app/views/cron/_edit.html.haml +15 -17
- data/app/views/cron/_index.html.haml +74 -67
- data/app/views/delayed_job_metrics/_index.html.haml +27 -0
- data/app/views/delayed_job_metrics/index.html.haml +1 -0
- data/app/views/delayed_job_workers/_index.html.haml +27 -0
- data/app/views/delayed_job_workers/index.html.haml +1 -0
- data/app/views/delayed_jobs/_index.html.haml +47 -52
- data/app/views/delayed_jobs/_show.html.haml +15 -13
- data/app/views/system_configurations/_edit.html.haml +14 -9
- data/app/views/system_configurations/_show.html.haml +18 -12
- data/config/brakeman.ignore +26 -0
- data/config/brakeman.yml +2 -0
- data/config/locales/en.yml +21 -3
- data/lib/app/controllers/concerns/core_delayed_job_metrics_controller.rb +35 -0
- data/lib/app/controllers/concerns/core_delayed_job_workers_controller.rb +35 -0
- data/lib/app/controllers/concerns/core_delayed_jobs_controller.rb +2 -3
- data/lib/app/jobs/cron/command.rb +1 -4
- data/lib/app/jobs/cron/record_delayed_job_metrics.rb +25 -0
- data/lib/app/jobs/cron/restart_orphaned_delayed_jobs.rb +44 -0
- data/lib/app/jobs/cron/server.rb +32 -15
- data/lib/app/jobs/cron/switchboard_sync_configuration.rb +2 -0
- data/lib/app/jobs/cron/switchboard_sync_models.rb +2 -0
- data/lib/app/jobs/cron/trim_collection.rb +1 -1
- data/lib/app/jobs/cron/trim_delayed_job_metrics.rb +29 -0
- data/lib/app/jobs/cron/trim_delayed_job_workers.rb +39 -0
- data/lib/app/jobs/cron/trim_failed_delayed_jobs.rb +2 -0
- data/lib/app/models/api_token.rb +9 -0
- data/lib/app/models/command_job.rb +12 -11
- data/lib/app/models/concerns/api_tokenable.rb +38 -0
- data/lib/app/models/concerns/aws_configuration.rb +65 -0
- data/lib/app/models/concerns/cdn_url.rb +7 -0
- data/lib/app/models/concerns/core_smtp_configuration.rb +65 -0
- data/lib/app/models/concerns/core_system_configuration.rb +18 -201
- data/lib/app/models/concerns/delayed_job_configuration.rb +24 -0
- data/lib/app/models/concerns/email_able.rb +6 -2
- data/lib/app/models/concerns/google_sso_configuration.rb +32 -0
- data/lib/app/models/concerns/search_able.rb +16 -0
- data/lib/app/models/concerns/server_process_able.rb +69 -0
- data/lib/app/models/concerns/slack_configuration.rb +38 -0
- data/lib/app/models/concerns/standard_model.rb +5 -2
- data/lib/app/models/concerns/switchboard_configuration.rb +43 -0
- data/lib/app/models/concerns/twilio_configuration.rb +37 -0
- data/lib/app/models/concerns/zendesk_configuration.rb +92 -0
- data/lib/app/models/{delayed_job.rb → delayed/backend/delayed_job.rb} +41 -0
- data/lib/app/models/delayed/jobs/metric.rb +61 -0
- data/lib/app/models/delayed/jobs/run.rb +40 -0
- data/lib/app/models/delayed/jobs/worker.rb +43 -0
- data/lib/app/models/delayed/plugins/time_keeper.rb +33 -0
- data/lib/app/models/delayed/worker.rb +24 -0
- data/lib/app/models/email_notification.rb +2 -1
- data/lib/app/models/email_template.rb +5 -6
- data/lib/app/models/notification.rb +12 -2
- data/lib/app/models/sms_notification.rb +9 -6
- data/lib/app/models/template.rb +12 -12
- data/lib/web47core/version.rb +1 -1
- data/lib/web47core.rb +33 -9
- metadata +114 -69
@@ -74,6 +74,47 @@ module Delayed
|
|
74
74
|
rescue StandardError
|
75
75
|
''
|
76
76
|
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Is this job running?
|
80
|
+
#
|
81
|
+
def running?
|
82
|
+
locked_by.present?
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Retrieve the host we are running on
|
87
|
+
#
|
88
|
+
def worker
|
89
|
+
Delayed::Jobs::Worker.where(host_name: worker_host_name, pid: worker_pid).first
|
90
|
+
rescue StandardError => error
|
91
|
+
App47Logger.log_warn 'Unable to fetch Worker information', error
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def worker_host_name
|
96
|
+
parts = locked_by.split
|
97
|
+
case parts.count
|
98
|
+
when 2
|
99
|
+
parts.first
|
100
|
+
when 3
|
101
|
+
parts[1]
|
102
|
+
else
|
103
|
+
raise "Unknown locked_by for delayed job #{parts}"
|
104
|
+
end.split(':').last
|
105
|
+
end
|
106
|
+
|
107
|
+
def worker_pid
|
108
|
+
parts = locked_by.split
|
109
|
+
case parts.count
|
110
|
+
when 2
|
111
|
+
parts.last
|
112
|
+
when 3
|
113
|
+
parts[2]
|
114
|
+
else
|
115
|
+
raise "Unknown locked_by for delayed job #{parts}"
|
116
|
+
end.split(':').last
|
117
|
+
end
|
77
118
|
end
|
78
119
|
end
|
79
120
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Jobs
|
5
|
+
#
|
6
|
+
# Hold the job metric information for a specific job, used to determine if the job should be auto restarted
|
7
|
+
#
|
8
|
+
class Metric
|
9
|
+
include StandardModel
|
10
|
+
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :name, type: String
|
15
|
+
field :count, type: Integer, default: 0
|
16
|
+
field :max, type: Float, default: 0
|
17
|
+
field :min, type: Float, default: 1_000_000_000
|
18
|
+
field :total, type: Float, default: 0
|
19
|
+
field :last_run_at, type: Time
|
20
|
+
|
21
|
+
#
|
22
|
+
# Validations
|
23
|
+
#
|
24
|
+
validates :name, uniqueness: true, presence: true
|
25
|
+
|
26
|
+
#
|
27
|
+
# Max allowed time for a currently running job
|
28
|
+
#
|
29
|
+
def max_allowed_seconds
|
30
|
+
send(max_allowed_method) * max_allowed_factor
|
31
|
+
rescue StandardError
|
32
|
+
max * 5
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Return the average time to run this job
|
37
|
+
#
|
38
|
+
def avg
|
39
|
+
count.zero? ? 0 : total / count
|
40
|
+
rescue StandardError
|
41
|
+
0
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
#
|
47
|
+
# Pull the method from system configuration to evalutate max allowed time
|
48
|
+
#
|
49
|
+
def max_allowed_method
|
50
|
+
@max_allowed_method ||= SystemConfiguration.delayed_job_max_allowed_method
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Pull the factor for max allowed when evaluating allowed time
|
55
|
+
#
|
56
|
+
def max_allowed_factor
|
57
|
+
@max_allowed_factor ||= SystemConfiguration.delayed_job_max_allowed_factor
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Jobs
|
5
|
+
#
|
6
|
+
# Single execution of a Job
|
7
|
+
#
|
8
|
+
class Run
|
9
|
+
include StandardModel
|
10
|
+
#
|
11
|
+
# Fields
|
12
|
+
#
|
13
|
+
field :name, type: String
|
14
|
+
field :locked_at, type: Time
|
15
|
+
field :locked_by, type: String
|
16
|
+
field :duration, type: Float, default: 0
|
17
|
+
#
|
18
|
+
# Relationships
|
19
|
+
#
|
20
|
+
belongs_to :worker, class_name: 'Delayed::Jobs::Worker'
|
21
|
+
#
|
22
|
+
# Validations
|
23
|
+
#
|
24
|
+
validates :name, presence: true
|
25
|
+
validates :locked_at, presence: true
|
26
|
+
validates :duration, numericality: { greater_than_or_equal_to: 0 }
|
27
|
+
#
|
28
|
+
# Callbacks
|
29
|
+
#
|
30
|
+
before_validation :record_duration
|
31
|
+
|
32
|
+
#
|
33
|
+
# Finish execution
|
34
|
+
#
|
35
|
+
def record_duration
|
36
|
+
self.duration = duration.zero? ? Time.now.utc - locked_at : duration
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Jobs
|
5
|
+
#
|
6
|
+
# Capture a specific worker process
|
7
|
+
#
|
8
|
+
class Worker
|
9
|
+
include StandardModel
|
10
|
+
include ServerProcessAble
|
11
|
+
#
|
12
|
+
# Relationships
|
13
|
+
#
|
14
|
+
has_many :runs, class_name: 'Delayed::Jobs::Run', dependent: :restrict
|
15
|
+
|
16
|
+
#
|
17
|
+
# Record a job relative to the worker
|
18
|
+
#
|
19
|
+
def record_job(job)
|
20
|
+
stop
|
21
|
+
runs.create!(name: job.display_name, locked_at: job.locked_at, locked_by: job.locked_by)
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Is this worker dead?, meaning has it reported in a timely manner
|
26
|
+
#
|
27
|
+
def dead?
|
28
|
+
last_check_in_at.present? ? check_in_limit > last_check_in_at : false
|
29
|
+
rescue StandardError
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
#
|
36
|
+
# Return the check in time limit based on if we are running or not
|
37
|
+
#
|
38
|
+
def check_in_limit
|
39
|
+
running? ? 3.hour.ago.utc : 1.minute.ago.utc
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Delayed
|
2
|
+
module Plugins
|
3
|
+
#
|
4
|
+
# Add callbacks to the lifecycle to capture two main aspects
|
5
|
+
# 1. When are workers checking in
|
6
|
+
# 2. How long jobs are taking
|
7
|
+
#
|
8
|
+
class TimeKeeper < Plugin
|
9
|
+
callbacks do |lifecycle|
|
10
|
+
lifecycle.before(:perform) do |_worker, job|
|
11
|
+
job.worker.start
|
12
|
+
rescue StandardError => error
|
13
|
+
App47Logger.log_warn 'before job perform', error
|
14
|
+
end
|
15
|
+
lifecycle.after(:perform) do |_worker, job|
|
16
|
+
job.worker.record_job(job)
|
17
|
+
rescue StandardError => error
|
18
|
+
App47Logger.log_warn 'after job perform', error
|
19
|
+
end
|
20
|
+
lifecycle.before(:loop) do
|
21
|
+
Delayed::Jobs::Worker.find_or_create_server.check_in
|
22
|
+
rescue StandardError => error
|
23
|
+
App47Logger.log_warn 'before worker loop', error
|
24
|
+
end
|
25
|
+
lifecycle.after(:loop) do
|
26
|
+
Delayed::Jobs::Worker.find_or_create_server.check_in
|
27
|
+
rescue StandardError => error
|
28
|
+
App47Logger.log_warn 'after worker loop', error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
#
|
5
|
+
# Override the start and stop of the worker itself to capture start/end of the worker lifecycle
|
6
|
+
#
|
7
|
+
class Worker
|
8
|
+
#
|
9
|
+
# Starting the worker
|
10
|
+
#
|
11
|
+
def start
|
12
|
+
super
|
13
|
+
Delayed::Jobs::Worker.find_or_create_server
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Stop the worker
|
18
|
+
#
|
19
|
+
def stop
|
20
|
+
Delayed::Jobs::Worker.find_server&.stop
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -17,6 +17,7 @@
|
|
17
17
|
#
|
18
18
|
# email = EmailNotification.new
|
19
19
|
# email.to = 'user@abc.com'
|
20
|
+
# email.recipient_name = 'users name'
|
20
21
|
# email.sender = 'me@abc.com'
|
21
22
|
# email.subject = 'Today is the day!'
|
22
23
|
# email.message = 'Day is today!'
|
@@ -217,7 +218,7 @@ class EmailNotification < Notification
|
|
217
218
|
return html_message if html_message.include?(tracker_url)
|
218
219
|
|
219
220
|
image_tag = "<img style='height:0;width:0;border:none;display:none;' src='#{tracker_url}' alt=''/></body>"
|
220
|
-
html_message.sub(%r{
|
221
|
+
html_message.sub(%r{</body>}, image_tag)
|
221
222
|
end
|
222
223
|
|
223
224
|
def subject_from_haml_text(haml_text, locals)
|
@@ -17,16 +17,15 @@ class EmailTemplate < Template
|
|
17
17
|
|
18
18
|
#
|
19
19
|
# Make sure the template is wrapped in html
|
20
|
+
#
|
20
21
|
def htmlize_template
|
21
|
-
if template.present? && !template.strip.start_with?(
|
22
|
-
self.template = "<body><pre>#{template}</pre></body>"
|
23
|
-
end
|
22
|
+
self.template = "<body><pre>#{template}</pre></body>" if template.present? && !template.strip.start_with?('<')
|
24
23
|
end
|
25
24
|
|
26
25
|
def valid_liquid_template
|
27
|
-
super && Liquid::Template.parse(
|
28
|
-
rescue
|
29
|
-
|
26
|
+
super && Liquid::Template.parse(subject).nil?
|
27
|
+
rescue StandardError => error
|
28
|
+
errors.add(:subject, "Invalid liquid text in subject: #{error.message}")
|
30
29
|
false
|
31
30
|
end
|
32
31
|
|
@@ -5,6 +5,7 @@
|
|
5
5
|
#
|
6
6
|
class Notification
|
7
7
|
include StandardModel
|
8
|
+
include SearchAble
|
8
9
|
#
|
9
10
|
# Constants
|
10
11
|
#
|
@@ -42,6 +43,7 @@ class Notification
|
|
42
43
|
field :error_message, type: String
|
43
44
|
field :last_viewed_at, type: Time
|
44
45
|
field :viewed_count, type: Integer, default: 0
|
46
|
+
field :recipient_name, type: String
|
45
47
|
#
|
46
48
|
# Relationships
|
47
49
|
#
|
@@ -100,10 +102,11 @@ class Notification
|
|
100
102
|
#
|
101
103
|
def finish_processing(processing_message = nil)
|
102
104
|
if processing_message.present?
|
103
|
-
|
105
|
+
assign_attributes state: STATE_INVALID, error_message: processing_message
|
104
106
|
else
|
105
|
-
|
107
|
+
assign_attributes state: STATE_PROCESSED, error_message: ''
|
106
108
|
end
|
109
|
+
save(validate: false)
|
107
110
|
end
|
108
111
|
|
109
112
|
#
|
@@ -242,6 +245,13 @@ class Notification
|
|
242
245
|
_type
|
243
246
|
end
|
244
247
|
|
248
|
+
#
|
249
|
+
# Support search fields
|
250
|
+
#
|
251
|
+
def search_fields
|
252
|
+
%w[to state recipient_name]
|
253
|
+
end
|
254
|
+
|
245
255
|
private
|
246
256
|
|
247
257
|
#
|
@@ -35,12 +35,15 @@ class SmsNotification < Notification
|
|
35
35
|
account_sid = config.twilio_account_id
|
36
36
|
auth_token = config.twilio_auth_token
|
37
37
|
client = Twilio::REST::Client.new account_sid, auth_token
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
twilio_message = if client.respond_to?(:account)
|
39
|
+
client.account.messages.create(body: message,
|
40
|
+
to: to,
|
41
|
+
from: config.twilio_phone_number)
|
42
|
+
else
|
43
|
+
client.messages.create(body: message,
|
44
|
+
to: to,
|
45
|
+
from: config.twilio_phone_number)
|
46
|
+
end
|
44
47
|
# We are saved in the calling class, no reason to save again
|
45
48
|
set sid: twilio_message.sid
|
46
49
|
end
|
data/lib/app/models/template.rb
CHANGED
@@ -20,18 +20,6 @@ class Template
|
|
20
20
|
validates :template, presence: true
|
21
21
|
validate :valid_liquid_template
|
22
22
|
|
23
|
-
private
|
24
|
-
|
25
|
-
#
|
26
|
-
# Ensure that the template is correct from a liquid statement
|
27
|
-
#
|
28
|
-
def valid_liquid_template
|
29
|
-
Liquid::Template.parse(self.template).nil?
|
30
|
-
rescue Exception => error
|
31
|
-
self.errors.add(:template, "Invalid liquid text in template: #{error.message}")
|
32
|
-
false
|
33
|
-
end
|
34
|
-
|
35
23
|
#
|
36
24
|
# Retrieve the template out of the project
|
37
25
|
#
|
@@ -45,4 +33,16 @@ class Template
|
|
45
33
|
rescue StandardError
|
46
34
|
nil
|
47
35
|
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
#
|
40
|
+
# Ensure that the template is correct from a liquid statement
|
41
|
+
#
|
42
|
+
def valid_liquid_template
|
43
|
+
Liquid::Template.parse(template).nil?
|
44
|
+
rescue StandardError => error
|
45
|
+
errors.add(:template, "Invalid liquid text in template: #{error.message}")
|
46
|
+
false
|
47
|
+
end
|
48
48
|
end
|
data/lib/web47core/version.rb
CHANGED
data/lib/web47core.rb
CHANGED
@@ -1,30 +1,48 @@
|
|
1
1
|
require 'web47core/config'
|
2
2
|
require 'app/models/concerns/app47_logger'
|
3
|
+
require 'app/models/concerns/api_tokenable'
|
4
|
+
require 'app/models/concerns/aws_configuration'
|
5
|
+
require 'app/models/concerns/core_system_configuration'
|
6
|
+
require 'app/models/concerns/core_account'
|
3
7
|
require 'app/models/concerns/cipher_able'
|
4
8
|
require 'app/models/concerns/cdn_url'
|
9
|
+
require 'app/models/concerns/delayed_job_configuration'
|
5
10
|
require 'app/models/concerns/email_able'
|
11
|
+
require 'app/models/concerns/encrypted_password'
|
12
|
+
require 'app/models/concerns/google_sso_configuration'
|
6
13
|
require 'app/models/concerns/search_able'
|
7
14
|
require 'app/models/concerns/role_able'
|
8
15
|
require 'app/models/concerns/time_zone_able'
|
16
|
+
require 'app/models/concerns/slack_configuration'
|
17
|
+
require 'app/models/concerns/server_process_able'
|
18
|
+
require 'app/models/concerns/core_smtp_configuration'
|
9
19
|
require 'app/models/concerns/standard_model'
|
10
20
|
require 'app/models/concerns/switchboard_able'
|
11
|
-
require 'app/models/concerns/
|
12
|
-
require 'app/models/concerns/core_account'
|
21
|
+
require 'app/models/concerns/switchboard_configuration'
|
13
22
|
require 'app/models/concerns/secure_fields'
|
14
|
-
require 'app/models/concerns/
|
23
|
+
require 'app/models/concerns/twilio_configuration'
|
24
|
+
require 'app/models/concerns/zendesk_configuration'
|
15
25
|
require 'app/models/command_job'
|
16
26
|
require 'app/models/command_job_log'
|
17
|
-
|
18
|
-
|
27
|
+
#
|
28
|
+
# Delayed jobs
|
29
|
+
#
|
30
|
+
require 'app/models/delayed/backend/delayed_job'
|
31
|
+
require 'app/models/delayed/plugins/time_keeper'
|
32
|
+
require 'app/models/delayed/jobs/metric'
|
33
|
+
require 'app/models/delayed/jobs/run'
|
34
|
+
require 'app/models/delayed/jobs/worker'
|
35
|
+
|
36
|
+
require 'app/models/api_token'
|
19
37
|
require 'app/models/notification'
|
20
|
-
require 'app/models/sms_notification'
|
21
38
|
require 'app/models/template'
|
22
|
-
require 'app/models/notification_template'
|
23
39
|
require 'app/models/email_notification'
|
24
40
|
require 'app/models/email_template'
|
41
|
+
require 'app/models/redis_configuration'
|
42
|
+
require 'app/models/notification_template'
|
25
43
|
require 'app/models/slack_notification'
|
26
|
-
require 'app/models/smtp_configuration'
|
27
44
|
require 'app/models/sms_notification'
|
45
|
+
require 'app/models/smtp_configuration'
|
28
46
|
#
|
29
47
|
# Cron
|
30
48
|
#
|
@@ -33,8 +51,12 @@ require 'app/jobs/cron/job'
|
|
33
51
|
require 'app/jobs/cron/tab'
|
34
52
|
require 'app/jobs/cron/job_tab'
|
35
53
|
require 'app/jobs/cron/command'
|
36
|
-
require 'app/jobs/cron/server'
|
37
54
|
require 'app/jobs/cron/trim_collection'
|
55
|
+
require 'app/jobs/cron/record_delayed_job_metrics'
|
56
|
+
require 'app/jobs/cron/restart_orphaned_delayed_jobs'
|
57
|
+
require 'app/jobs/cron/trim_delayed_job_metrics'
|
58
|
+
require 'app/jobs/cron/trim_delayed_job_workers'
|
59
|
+
require 'app/jobs/cron/server'
|
38
60
|
require 'app/jobs/cron/switchboard_sync_configuration'
|
39
61
|
require 'app/jobs/cron/switchboard_sync_models'
|
40
62
|
require 'app/jobs/cron/trim_audit_logs'
|
@@ -60,3 +82,5 @@ require 'app/controllers/concerns/core_controller'
|
|
60
82
|
require 'app/controllers/concerns/core_system_configuration_controller'
|
61
83
|
require 'app/controllers/concerns/core_cron_controller'
|
62
84
|
require 'app/controllers/concerns/core_delayed_jobs_controller'
|
85
|
+
require 'app/controllers/concerns/core_delayed_job_metrics_controller'
|
86
|
+
require 'app/controllers/concerns/core_delayed_job_workers_controller'
|