web47core 2.0.0 → 3.0.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 +4 -4
- data/README.md +111 -41
- data/app/controllers/status_controller.rb +15 -4
- 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/application_job.rb +0 -1
- 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/tab.rb +1 -1
- data/lib/app/jobs/cron/trim_collection.rb +1 -1
- data/lib/app/jobs/cron/trim_command_jobs.rb +28 -0
- 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 +375 -0
- data/lib/app/models/command_job_log.rb +33 -0
- data/lib/app/models/concerns/api_tokenable.rb +38 -0
- data/lib/app/models/concerns/aws_configuration.rb +41 -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 +21 -204
- data/lib/app/models/concerns/delayed_job_configuration.rb +24 -0
- data/lib/app/models/concerns/email_able.rb +7 -3
- 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 +8 -9
- 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/notification_template.rb +1 -1
- data/lib/app/models/sms_notification.rb +9 -6
- data/lib/app/models/smtp_configuration.rb +3 -3
- data/lib/app/models/template.rb +12 -12
- data/lib/web47core/version.rb +1 -1
- data/lib/web47core.rb +35 -9
- metadata +147 -216
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Switchboard configuration, both the fields and methods needed to determine configuration
|
5
|
+
#
|
6
|
+
module SwitchboardConfiguration
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
#
|
9
|
+
# Switchboard configuration
|
10
|
+
#
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
# Switchboard
|
14
|
+
field :switchboard_base_url, type: String, default: 'https://switchboard.app47.com'
|
15
|
+
field :switchboard_stack_id, type: String
|
16
|
+
field :switchboard_stack_api_token, type: String
|
17
|
+
field :switchboard_last_sync_at, type: Time
|
18
|
+
#
|
19
|
+
# Validations
|
20
|
+
#
|
21
|
+
validates :switchboard_base_url, url: true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Make sure the password doesn't get blanked out on an update
|
27
|
+
#
|
28
|
+
def secure_fields
|
29
|
+
super + %i[switchboard_stack_api_token]
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Public: Determine if switchboard is configured
|
34
|
+
#
|
35
|
+
# Examples
|
36
|
+
#
|
37
|
+
# switchboard_configured?
|
38
|
+
# # => true || false
|
39
|
+
#
|
40
|
+
def switchboard_configured?
|
41
|
+
[switchboard_base_url.present?, switchboard_stack_api_token.present?, switchboard_stack_id.present?].all?
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Twilio configuration, both fields and methods to determine configuration
|
5
|
+
#
|
6
|
+
module TwilioConfiguration
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
#
|
9
|
+
# The Twilio Configuration
|
10
|
+
#
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
field :twilio_account_id, type: String
|
14
|
+
field :twilio_auth_token, type: String
|
15
|
+
field :twilio_phone_number, type: String
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Make sure the password doesn't get blanked out on an update
|
21
|
+
#
|
22
|
+
def secure_fields
|
23
|
+
super + %i[twilio_auth_token]
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Determine if twilio is configured at a system configuration
|
28
|
+
#
|
29
|
+
# Examples
|
30
|
+
#
|
31
|
+
# twilio_configured??
|
32
|
+
# # => true || false
|
33
|
+
#
|
34
|
+
def twilio_configured?
|
35
|
+
[twilio_account_id.present?, twilio_auth_token.present?, twilio_phone_number.present?].all?
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Add zendesk capability to an object to integrate via JWT with Zendesk. Most commonly this will be added
|
5
|
+
# to SystemConfiguration, however this can also be added to a different object (i.e., switchboard).
|
6
|
+
#
|
7
|
+
module ZendeskConfiguration
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :zendesk_token, type: String
|
15
|
+
field :zendesk_base_url, type: String, default: 'https://app47.zendesk.com'
|
16
|
+
field :zendesk_documentation_path, type: String, default: 'hc'
|
17
|
+
field :zendesk_support_path, type: String, default: 'hc/en-us/requests'
|
18
|
+
field :zendesk_updates_path, type: String, default: 'hc'
|
19
|
+
#
|
20
|
+
# Validations
|
21
|
+
#
|
22
|
+
validates :zendesk_base_url, url: true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Make sure the password doesn't get blanked out on an update
|
28
|
+
#
|
29
|
+
def secure_fields
|
30
|
+
super + %i[zendesk_token]
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Return the zendesk documentation URL
|
35
|
+
#
|
36
|
+
def zendesk_documentation_url(user = nil)
|
37
|
+
zendesk_url(forward_to: zendesk_documentation_path, user: user)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Return the zendesk support URL
|
42
|
+
#
|
43
|
+
def zendesk_requests_url(user = nil)
|
44
|
+
zendesk_url(forward_to: zendesk_support_path, user: user)
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Return the zendesk support URL
|
49
|
+
#
|
50
|
+
def zendesk_new_request_url(user = nil)
|
51
|
+
zendesk_url(forward_to: "#{zendesk_support_path}/new", user: user)
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Return the zendesk update URL
|
56
|
+
#
|
57
|
+
def zendesk_updates_url(user = nil)
|
58
|
+
zendesk_url(forward_to: zendesk_updates_path, user: user)
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Generate a Zendesk URL
|
63
|
+
#
|
64
|
+
# If a user is passed in and Zendesk is configured then return a JWT enabled URL for
|
65
|
+
# SSO authentication to Zendesk.
|
66
|
+
#
|
67
|
+
def zendesk_url(forward_to: zendesk_documentation_path, user: nil)
|
68
|
+
path = if zendesk_configured? && user.present?
|
69
|
+
time_now = Time.now.to_i
|
70
|
+
jti = "#{time_now}/#{rand(36**64).to_s(36)}"
|
71
|
+
payload = { jwt: JWT.encode({ iat: time_now, # Seconds since epoch, determine when this token is stale
|
72
|
+
jti: jti, # Unique token identifier, helps prevent replay attacks
|
73
|
+
name: user.name,
|
74
|
+
email: user.email }, zendesk_token),
|
75
|
+
return_to: CGI.escape([zendesk_base_url, forward_to].join('/')) }
|
76
|
+
['access/jwt', payload.to_query].join('?')
|
77
|
+
else
|
78
|
+
forward_to
|
79
|
+
end
|
80
|
+
[zendesk_base_url, path].join('/')
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Is zendesk configured?
|
85
|
+
#
|
86
|
+
def zendesk_configured?
|
87
|
+
[zendesk_token.present?,
|
88
|
+
zendesk_base_url.present?,
|
89
|
+
zendesk_documentation_path.present?,
|
90
|
+
zendesk_support_path.present?].all?
|
91
|
+
end
|
92
|
+
end
|
@@ -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_with_exception
|
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
|
@@ -10,10 +10,10 @@ class SmtpConfiguration
|
|
10
10
|
field :port, type: Integer, default: 587
|
11
11
|
field :authentication_method, type: String
|
12
12
|
field :confirmation_token, type: String
|
13
|
-
field :confirmed, type: Boolean, default: false
|
13
|
+
field :confirmed, type: Mongoid::Boolean, default: false
|
14
14
|
field :verification_message, type: String
|
15
|
-
field :active, type: Boolean, default: false
|
16
|
-
field :ssl, type: Boolean, default: false
|
15
|
+
field :active, type: Mongoid::Boolean, default: false
|
16
|
+
field :ssl, type: Mongoid::Boolean, default: false
|
17
17
|
field :server_name, type: String
|
18
18
|
field :username, type: String
|
19
19
|
field :password, type: String
|
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,28 +1,47 @@
|
|
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'
|
6
12
|
require 'app/models/concerns/search_able'
|
7
13
|
require 'app/models/concerns/role_able'
|
8
14
|
require 'app/models/concerns/time_zone_able'
|
15
|
+
require 'app/models/concerns/slack_configuration'
|
16
|
+
require 'app/models/concerns/server_process_able'
|
17
|
+
require 'app/models/concerns/core_smtp_configuration'
|
9
18
|
require 'app/models/concerns/standard_model'
|
10
19
|
require 'app/models/concerns/switchboard_able'
|
11
|
-
require 'app/models/concerns/
|
12
|
-
require 'app/models/concerns/core_account'
|
20
|
+
require 'app/models/concerns/switchboard_configuration'
|
13
21
|
require 'app/models/concerns/secure_fields'
|
14
|
-
require 'app/models/concerns/
|
15
|
-
require 'app/models/
|
16
|
-
require 'app/models/
|
22
|
+
require 'app/models/concerns/twilio_configuration'
|
23
|
+
require 'app/models/concerns/zendesk_configuration'
|
24
|
+
require 'app/models/command_job'
|
25
|
+
require 'app/models/command_job_log'
|
26
|
+
#
|
27
|
+
# Delayed jobs
|
28
|
+
#
|
29
|
+
require 'app/models/delayed/backend/delayed_job'
|
30
|
+
require 'app/models/delayed/plugins/time_keeper'
|
31
|
+
require 'app/models/delayed/jobs/metric'
|
32
|
+
require 'app/models/delayed/jobs/run'
|
33
|
+
require 'app/models/delayed/jobs/worker'
|
34
|
+
|
35
|
+
require 'app/models/api_token'
|
17
36
|
require 'app/models/notification'
|
18
|
-
require 'app/models/sms_notification'
|
19
37
|
require 'app/models/template'
|
20
|
-
require 'app/models/notification_template'
|
21
38
|
require 'app/models/email_notification'
|
22
39
|
require 'app/models/email_template'
|
40
|
+
require 'app/models/redis_configuration'
|
41
|
+
require 'app/models/notification_template'
|
23
42
|
require 'app/models/slack_notification'
|
24
|
-
require 'app/models/smtp_configuration'
|
25
43
|
require 'app/models/sms_notification'
|
44
|
+
require 'app/models/smtp_configuration'
|
26
45
|
#
|
27
46
|
# Cron
|
28
47
|
#
|
@@ -31,13 +50,18 @@ require 'app/jobs/cron/job'
|
|
31
50
|
require 'app/jobs/cron/tab'
|
32
51
|
require 'app/jobs/cron/job_tab'
|
33
52
|
require 'app/jobs/cron/command'
|
34
|
-
require 'app/jobs/cron/server'
|
35
53
|
require 'app/jobs/cron/trim_collection'
|
54
|
+
require 'app/jobs/cron/record_delayed_job_metrics'
|
55
|
+
require 'app/jobs/cron/restart_orphaned_delayed_jobs'
|
56
|
+
require 'app/jobs/cron/trim_delayed_job_metrics'
|
57
|
+
require 'app/jobs/cron/trim_delayed_job_workers'
|
58
|
+
require 'app/jobs/cron/server'
|
36
59
|
require 'app/jobs/cron/switchboard_sync_configuration'
|
37
60
|
require 'app/jobs/cron/switchboard_sync_models'
|
38
61
|
require 'app/jobs/cron/trim_audit_logs'
|
39
62
|
require 'app/jobs/cron/trim_cron_servers'
|
40
63
|
require 'app/jobs/cron/trim_failed_delayed_jobs'
|
64
|
+
require 'app/jobs/cron/trim_command_jobs'
|
41
65
|
require 'app/jobs/cron/trim_notifications'
|
42
66
|
#
|
43
67
|
# Audit Logs
|
@@ -57,3 +81,5 @@ require 'app/controllers/concerns/core_controller'
|
|
57
81
|
require 'app/controllers/concerns/core_system_configuration_controller'
|
58
82
|
require 'app/controllers/concerns/core_cron_controller'
|
59
83
|
require 'app/controllers/concerns/core_delayed_jobs_controller'
|
84
|
+
require 'app/controllers/concerns/core_delayed_job_metrics_controller'
|
85
|
+
require 'app/controllers/concerns/core_delayed_job_workers_controller'
|