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,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Capture command log messages for a given job
|
5
|
+
#
|
6
|
+
class CommandJobLog
|
7
|
+
include StandardModel
|
8
|
+
#
|
9
|
+
# Fields
|
10
|
+
#
|
11
|
+
field :message, type: String
|
12
|
+
field :command, type: String
|
13
|
+
field :dir, type: String
|
14
|
+
#
|
15
|
+
# Relationships
|
16
|
+
#
|
17
|
+
belongs_to :job, inverse_of: :logs, class_name: 'CommandJob'
|
18
|
+
#
|
19
|
+
# Validations
|
20
|
+
#
|
21
|
+
validates :message, presence: true
|
22
|
+
|
23
|
+
#
|
24
|
+
# Display message
|
25
|
+
#
|
26
|
+
def display_message
|
27
|
+
if dir.present?
|
28
|
+
"Dir: #{dir}\nCommand: #{command}\nOutput: #{message}"
|
29
|
+
else
|
30
|
+
message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# API tokenable, support for the api token in user, but also may be applied elsewhere
|
5
|
+
#
|
6
|
+
module ApiTokenable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
# store api token
|
12
|
+
field :api_token, type: String
|
13
|
+
# if the api token should be reset
|
14
|
+
field :reset_api_token, type: Mongoid::Boolean, default: true
|
15
|
+
field :last_authenticated_at, type: Time
|
16
|
+
field :last_authenticated_ip, type: String
|
17
|
+
# call back to reset the api token.
|
18
|
+
before_save :assign_api_token, if: :reset_api_token
|
19
|
+
# set the index on api token
|
20
|
+
index({ api_token: 1 }, background: true)
|
21
|
+
|
22
|
+
def cycle_api_token
|
23
|
+
self.set api_token: SecureRandom.urlsafe_base64
|
24
|
+
api_token
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
#
|
30
|
+
# set the api token
|
31
|
+
#
|
32
|
+
def assign_api_token
|
33
|
+
self.reset_api_token = false
|
34
|
+
self.api_token = SecureRandom.urlsafe_base64
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# AWS Configuration
|
5
|
+
#
|
6
|
+
module AwsConfiguration
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :aws_region, type: String
|
15
|
+
field :aws_access_key_id, type: String
|
16
|
+
field :aws_secret_access_key, type: String
|
17
|
+
field :aws_auto_scaling_group_name, type: String
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Make sure the password doesn't get blanked out on an update
|
23
|
+
#
|
24
|
+
def secure_fields
|
25
|
+
super + %i[aws_access_secret]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Determine if AWS is configured
|
30
|
+
#
|
31
|
+
def aws_configured?
|
32
|
+
[aws_region.present?, aws_access_key_id.present?, aws_secret_access_key.present?].all?
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Determine if auto scaling group is configured
|
37
|
+
#
|
38
|
+
def aws_auto_scaling_configured?
|
39
|
+
aws_configured? && aws_auto_scaling_group_name.present?
|
40
|
+
end
|
41
|
+
end
|
@@ -17,6 +17,13 @@
|
|
17
17
|
#
|
18
18
|
module CdnUrl
|
19
19
|
extend ActiveSupport::Concern
|
20
|
+
#
|
21
|
+
# Constants
|
22
|
+
#
|
23
|
+
STYLE_S3_FILE_PATH = ':class/:attachment/:id/:style.:extension' unless defined? STYLE_S3_FILE_PATH
|
24
|
+
STYLE_FILE_PATH = 'public/system/:class/:attachment/:id/:style.:extension' unless defined? STYLE_FILE_PATH
|
25
|
+
STYLE_S3_FILE_URL = ':s3_domain_url' unless defined? STYLE_S3_FILE_URL
|
26
|
+
STYLE_FILE_URL = ':rails_root/public/system/:class/:attachment/:id/:style.:extension' unless defined? STYLE_FILE_URL
|
20
27
|
|
21
28
|
def method_missing(method, *args)
|
22
29
|
if method.to_s.start_with? 'cdn_'
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# SMTP Configuration
|
5
|
+
#
|
6
|
+
module CoreSmtpConfiguration
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :default_email, type: String, default: 'support@app47.com'
|
15
|
+
field :support_email, type: String, default: 'support@app47.com'
|
16
|
+
field :smtp_name, type: String
|
17
|
+
field :smtp_address, type: String
|
18
|
+
field :smtp_domain, type: String
|
19
|
+
field :smtp_port, type: Integer, default: 587
|
20
|
+
field :smtp_user_name, type: String
|
21
|
+
field :smtp_password, type: String
|
22
|
+
field :smtp_enable_starttls_auto, type: Mongoid::Boolean, default: false
|
23
|
+
field :mailgun_api_key, type: String
|
24
|
+
field :email_notification_ttl, type: Integer, default: 180
|
25
|
+
end
|
26
|
+
base.extend SmtpClassMethods
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Class methods for smtp configuration
|
31
|
+
#
|
32
|
+
module SmtpClassMethods
|
33
|
+
def smtp_configuration
|
34
|
+
output = {}
|
35
|
+
config = configuration
|
36
|
+
fields = %w[name address domain port user_name password enable_starttls_auto]
|
37
|
+
fields.each do |field|
|
38
|
+
field_name = "smtp_#{field}".to_sym
|
39
|
+
output[field.to_sym] = config.send(field_name)
|
40
|
+
end
|
41
|
+
output
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Make sure the password doesn't get blanked out on an update
|
47
|
+
#
|
48
|
+
def secure_fields
|
49
|
+
super + %i[smtp_password mailgun_api_key]
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Determine if SMTP is configured
|
54
|
+
#
|
55
|
+
def smtp_configured?
|
56
|
+
smtp_name.present? && smtp_address.present? && smtp_domain.present?
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Determine if mailgun is configured
|
61
|
+
#
|
62
|
+
def mail_gun_configured?
|
63
|
+
smtp_configured? && mailgun_api_key.present?
|
64
|
+
end
|
65
|
+
end
|
@@ -1,112 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
#
|
4
|
+
# The System configuration. Various configuration items that can be updated/defined at run time
|
5
|
+
#
|
6
|
+
# Use of this class allows you to simply ask for the configuration parameter directly without
|
7
|
+
# first having to get an instance of it.
|
8
|
+
#
|
9
|
+
# SystemConfiguration.queue_impl #=> 'RedisQueue'
|
10
|
+
#
|
11
|
+
# This method only is allowed for accessors, you should NEVER set values on the SystemConfiguration
|
12
|
+
# unless you are updating via the Admin or Stack UI, or during testing to setup a specific configuration
|
13
|
+
# for that.
|
14
|
+
#
|
3
15
|
module CoreSystemConfiguration
|
4
16
|
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
# The System configuration. Various configuration items that can be updated/defined at run time
|
7
|
-
#
|
8
|
-
# Use of this class allows you to simply ask for the configuration parameter directly without
|
9
|
-
# first having to get an instance of it.
|
10
|
-
#
|
11
|
-
# SystemConfiguration.queue_impl #=> 'RedisQueue'
|
12
|
-
#
|
13
|
-
# This method only is allowed for accessors, you should NEVER set values on the SystemConfiguration
|
14
|
-
# unless you are updating via the Admin or Stack UI, or during testing to setup a specific configuration
|
15
|
-
# for that.
|
16
|
-
#
|
17
|
+
|
17
18
|
def self.included(base)
|
18
19
|
base.class_eval do
|
19
20
|
attr_accessor :configuration
|
21
|
+
|
20
22
|
#
|
21
23
|
# Fields
|
22
24
|
#
|
23
25
|
field :environment, type: String, default: 'test'
|
24
|
-
field :fips_mode, type: Boolean, default: false
|
26
|
+
field :fips_mode, type: Mongoid::Boolean, default: false
|
25
27
|
field :fav_icon_path, { type: String, default: '/favicon.ico' }
|
26
28
|
field :stack_logo_path, { type: String, default: 'ui-company-logo.png' }
|
27
29
|
field :primary_stylesheet, { type: String, default: 'app47' }
|
28
30
|
field :short_cache, { type: Integer, default: 1 }
|
29
31
|
field :medium_cache, { type: Integer, default: 5 }
|
30
32
|
field :long_cache, { type: Integer, default: 15 }
|
31
|
-
# SMTP configuration
|
32
|
-
field :default_email, type: String, default: 'support@app47.com'
|
33
|
-
field :support_email, type: String, default: 'support@app47.com'
|
34
|
-
field :smtp_name, type: String
|
35
|
-
field :smtp_address, type: String
|
36
|
-
field :smtp_domain, type: String
|
37
|
-
field :smtp_port, type: Integer, default: 587
|
38
|
-
field :smtp_user_name, type: String
|
39
|
-
field :smtp_password, type: String
|
40
|
-
field :smtp_enable_starttls_auto, type: Boolean
|
41
|
-
field :mailgun_api_key, type: String
|
42
|
-
# Twillio support
|
43
|
-
field :twilio_account_id, type: String
|
44
|
-
field :twilio_auth_token, type: String
|
45
|
-
field :twilio_phone_number, type: String
|
46
33
|
# URLs
|
47
34
|
field :base_url, type: String
|
48
35
|
field :cdn_url, type: String
|
49
|
-
|
50
|
-
field :slack_api_url, type: String
|
51
|
-
field :slack_support_channel, type: String, default: 'support'
|
52
|
-
field :slack_sales_channel, type: String, default: 'sales'
|
36
|
+
field :asset_cdn_url, type: String
|
53
37
|
# Time Zone Support
|
54
38
|
field :default_time_zone, type: String, default: 'US/Eastern'
|
55
|
-
# AWS
|
56
|
-
field :aws_region, type: String
|
57
|
-
field :aws_access_key_id, type: String
|
58
|
-
field :aws_secret_access_key, type: String
|
59
|
-
field :aws_auto_scaling_group_name, type: String
|
60
|
-
# Zendesk
|
61
|
-
field :zendesk_token, type: String
|
62
|
-
field :zendesk_base_url, type: String, default: 'https://app47.zendesk.com'
|
63
|
-
field :zendesk_documentation_path, type: String, default: 'hc'
|
64
|
-
field :zendesk_support_path, type: String, default: 'hc/en-us/requests'
|
65
|
-
field :zendesk_updates_path, type: String, default: 'hc'
|
66
|
-
# Switchboard
|
67
|
-
field :switchboard_base_url, type: String, default: 'https://switchboard.app47.com'
|
68
|
-
field :switchboard_stack_id, type: String
|
69
|
-
field :switchboard_stack_api_token, type: String
|
70
|
-
field :switchboard_last_sync_at, type: Time
|
71
39
|
# TTLs
|
72
40
|
field :user_model_audit_log_ttl, type: Integer, default: 365
|
73
|
-
field :slack_notification_ttl, type: Integer, default: 5
|
74
|
-
field :email_notification_ttl, type: Integer, default: 180
|
75
41
|
#
|
76
42
|
# Validations
|
77
43
|
#
|
78
44
|
validates :environment, presence: true, uniqueness: true
|
79
|
-
validates :slack_support_channel, presence: true
|
80
|
-
validates :slack_sales_channel, presence: true
|
81
45
|
validates :default_time_zone, presence: true
|
82
|
-
validates :switchboard_base_url, url: true
|
83
|
-
validates :zendesk_base_url, url: true
|
84
46
|
end
|
85
47
|
base.extend ClassMethods
|
86
48
|
end
|
87
49
|
|
50
|
+
#
|
51
|
+
# Class methods for SystemConfiguration
|
52
|
+
#
|
88
53
|
module ClassMethods
|
89
54
|
def configuration
|
90
55
|
SystemConfiguration.find_or_create_by!(environment: Rails.env)
|
91
56
|
end
|
92
57
|
|
93
|
-
def smtp_configuration
|
94
|
-
output = {}
|
95
|
-
config = configuration
|
96
|
-
fields = %w[name address domain port user_name password enable_starttls_auto]
|
97
|
-
fields.each do |field|
|
98
|
-
field_name = "smtp_#{field}".to_sym
|
99
|
-
output[field.to_sym] = config.send(field_name)
|
100
|
-
end
|
101
|
-
output
|
102
|
-
end
|
103
|
-
|
104
58
|
#
|
105
59
|
# NOTE: Currently ignored Codacy issue: When using 'method_missing', fall back on 'super'
|
106
60
|
#
|
107
|
-
def method_missing(method,
|
61
|
+
def method_missing(method, ...)
|
108
62
|
if configuration.respond_to?(method)
|
109
|
-
configuration.send(method,
|
63
|
+
configuration.send(method, ...)
|
110
64
|
else
|
111
65
|
super
|
112
66
|
end
|
@@ -121,18 +75,6 @@ module CoreSystemConfiguration
|
|
121
75
|
end
|
122
76
|
end
|
123
77
|
|
124
|
-
#
|
125
|
-
# Make sure the password doesn't get blanked out on an update
|
126
|
-
#
|
127
|
-
def secure_fields
|
128
|
-
super + %i[smtp_password
|
129
|
-
aws_access_secret
|
130
|
-
mailgun_api_key
|
131
|
-
switchboard_stack_api_token
|
132
|
-
twilio_auth_token
|
133
|
-
zendesk_token]
|
134
|
-
end
|
135
|
-
|
136
78
|
#
|
137
79
|
# Cache times in minutes
|
138
80
|
#
|
@@ -147,129 +89,4 @@ module CoreSystemConfiguration
|
|
147
89
|
def long_cache_time
|
148
90
|
long_cache.minutes
|
149
91
|
end
|
150
|
-
|
151
|
-
#
|
152
|
-
# Determine if SMTP is configured
|
153
|
-
#
|
154
|
-
def smtp_configured?
|
155
|
-
smtp_name.present? && smtp_address.present? && smtp_domain.present?
|
156
|
-
end
|
157
|
-
|
158
|
-
#
|
159
|
-
# Determine if mailgun is configured
|
160
|
-
#
|
161
|
-
def mail_gun_configured?
|
162
|
-
smtp_configured? && mailgun_api_key.present?
|
163
|
-
end
|
164
|
-
|
165
|
-
#
|
166
|
-
# Determine if AWS is configured
|
167
|
-
#
|
168
|
-
def aws_configured?
|
169
|
-
[aws_region.present?, aws_access_key_id.present?, aws_secret_access_key.present?].all?
|
170
|
-
end
|
171
|
-
|
172
|
-
#
|
173
|
-
# Determine if auto scaling group is configured
|
174
|
-
#
|
175
|
-
def aws_auto_scaling_configured?
|
176
|
-
aws_configured? && aws_auto_scaling_group_name.present?
|
177
|
-
end
|
178
|
-
|
179
|
-
#
|
180
|
-
# Return the zendesk documentation URL
|
181
|
-
#
|
182
|
-
def zendesk_documentation_url(user = nil)
|
183
|
-
zendesk_url(forward_to: zendesk_documentation_path, user: user)
|
184
|
-
end
|
185
|
-
|
186
|
-
#
|
187
|
-
# Return the zendesk support URL
|
188
|
-
#
|
189
|
-
def zendesk_requests_url(user = nil)
|
190
|
-
zendesk_url(forward_to: zendesk_support_path, user: user)
|
191
|
-
end
|
192
|
-
|
193
|
-
#
|
194
|
-
# Return the zendesk support URL
|
195
|
-
#
|
196
|
-
def zendesk_new_request_url(user = nil)
|
197
|
-
zendesk_url(forward_to: "#{zendesk_support_path}/new", user: user)
|
198
|
-
end
|
199
|
-
|
200
|
-
#
|
201
|
-
# Return the zendesk update URL
|
202
|
-
#
|
203
|
-
def zendesk_updates_url(user = nil)
|
204
|
-
zendesk_url(forward_to: zendesk_updates_path, user: user)
|
205
|
-
end
|
206
|
-
|
207
|
-
#
|
208
|
-
# Generate a Zendesk URL
|
209
|
-
#
|
210
|
-
# If a user is passed in and Zendesk is configured then return a JWT enabled URL for
|
211
|
-
# SSO authentication to Zendesk.
|
212
|
-
#
|
213
|
-
def zendesk_url(forward_to: zendesk_documentation_path, user: nil)
|
214
|
-
config = SystemConfiguration.configuration
|
215
|
-
path = if config.zendesk_configured? && user.present?
|
216
|
-
time_now = Time.now.to_i
|
217
|
-
jti = "#{time_now}/#{rand(36 ** 64).to_s(36)}"
|
218
|
-
payload = { jwt: JWT.encode({ iat: time_now, # Seconds since epoch, determine when this token is stale
|
219
|
-
jti: jti, # Unique token identifier, helps prevent replay attacks
|
220
|
-
name: user.name,
|
221
|
-
email: user.email }, config.zendesk_token),
|
222
|
-
return_to: CGI.escape([config.zendesk_base_url, forward_to].join('/')) }
|
223
|
-
['access/jwt', payload.to_query].join('?')
|
224
|
-
else
|
225
|
-
forward_to
|
226
|
-
end
|
227
|
-
[config.zendesk_base_url, path].join('/')
|
228
|
-
end
|
229
|
-
|
230
|
-
#
|
231
|
-
# Is zendesk configured?
|
232
|
-
#
|
233
|
-
def zendesk_configured?
|
234
|
-
[zendesk_token.present?,
|
235
|
-
zendesk_base_url.present?,
|
236
|
-
zendesk_documentation_path.present?,
|
237
|
-
zendesk_support_path.present?].all?
|
238
|
-
end
|
239
|
-
|
240
|
-
#
|
241
|
-
# Public: Determine if switchboard is configured
|
242
|
-
#
|
243
|
-
# Examples
|
244
|
-
#
|
245
|
-
# switchboard_configured?
|
246
|
-
# # => true || false
|
247
|
-
#
|
248
|
-
def switchboard_configured?
|
249
|
-
[switchboard_base_url.present?, switchboard_stack_api_token.present?, switchboard_stack_id.present?].all?
|
250
|
-
end
|
251
|
-
|
252
|
-
#
|
253
|
-
# Determine if twillio is configured at a system configuration
|
254
|
-
#
|
255
|
-
# Examples
|
256
|
-
#
|
257
|
-
# switchboard_configured?
|
258
|
-
# # => true || false
|
259
|
-
#
|
260
|
-
def twilio_configured?
|
261
|
-
[twilio_account_id.present?, twilio_auth_token.present?, twilio_phone_number.present?].all?
|
262
|
-
end
|
263
|
-
|
264
|
-
#
|
265
|
-
# Determine if Slack is configured
|
266
|
-
#
|
267
|
-
# Examples
|
268
|
-
#
|
269
|
-
# switchboard_configured?
|
270
|
-
# # => true || false
|
271
|
-
#
|
272
|
-
def slack_configured?
|
273
|
-
slack_api_url.present?
|
274
|
-
end
|
275
92
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Slack Configuration to be used inside of SystemConfiguration
|
5
|
+
#
|
6
|
+
module DelayedJobConfiguration
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :delayed_job_max_allowed_method, type: String, default: 'max'
|
15
|
+
field :delayed_job_max_allowed_factor, type: Integer, default: 5
|
16
|
+
field :delayed_job_restart_orphaned, type: Mongoid::Boolean, default: false
|
17
|
+
#
|
18
|
+
# Validations
|
19
|
+
#
|
20
|
+
validates :delayed_job_max_allowed_method, inclusion: { in: %w[max min avg] }
|
21
|
+
validates :delayed_job_max_allowed_factor, numericality: { greater_than: 0 }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -17,7 +17,7 @@ module EmailAble
|
|
17
17
|
field :email_bounced_at, type: Time
|
18
18
|
field :email_bounce_reason, type: String
|
19
19
|
field :unconfirmed_email, type: String
|
20
|
-
field :email_enabled, type: Boolean, default: true
|
20
|
+
field :email_enabled, type: Mongoid::Boolean, default: true
|
21
21
|
#
|
22
22
|
# Validations
|
23
23
|
#
|
@@ -61,7 +61,7 @@ module EmailAble
|
|
61
61
|
#
|
62
62
|
# Reset the bounced email
|
63
63
|
#
|
64
|
-
def reset_bounce_status
|
64
|
+
def reset_bounce_status(current_member = nil)
|
65
65
|
return unless SystemConfiguration.mail_gun_configured? && email_bounced?
|
66
66
|
|
67
67
|
reset_url = "https://api.mailgun.net/v3/#{SystemConfiguration.smtp_domain}/bounces/#{CGI.escape(email)}"
|
@@ -69,7 +69,11 @@ module EmailAble
|
|
69
69
|
rescue RestClient::Exception => error
|
70
70
|
log_error "Unable to reset email bounce status: #{inspect}", error
|
71
71
|
ensure
|
72
|
-
|
72
|
+
if current_member.present?
|
73
|
+
update_and_log current_member, email_bounced_at: nil, email_bounce_reason: nil
|
74
|
+
else
|
75
|
+
set email_bounced_at: nil, email_bounce_reason: nil
|
76
|
+
end
|
73
77
|
end
|
74
78
|
|
75
79
|
#
|
@@ -39,6 +39,22 @@ module SearchAble
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
def method_missing(method, *args)
|
43
|
+
if method.to_s.start_with? 'sorted_'
|
44
|
+
send(method.to_s.sub(/^sorted_/, '')).asc(:sort_text)
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def respond_to_missing?(method_name, include_private = false)
|
51
|
+
super || method_name.to_s.start_with?('sorted_')
|
52
|
+
end
|
53
|
+
|
54
|
+
def respond_to?(method, include_private = false)
|
55
|
+
super || method.to_s.start_with?('sorted_')
|
56
|
+
end
|
57
|
+
|
42
58
|
#
|
43
59
|
# Place holder to call to allow for work to be done before we gather up search text fields
|
44
60
|
#
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Mixin for objects that act as servers
|
5
|
+
#
|
6
|
+
module ServerProcessAble
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :host_name, type: String
|
15
|
+
field :pid, type: Integer
|
16
|
+
field :running, type: Mongoid::Boolean, default: false
|
17
|
+
field :last_check_in_at, type: Time
|
18
|
+
#
|
19
|
+
# Validations
|
20
|
+
#
|
21
|
+
validates :host_name, presence: true
|
22
|
+
validates :pid, presence: true
|
23
|
+
end
|
24
|
+
base.extend ClassMethods
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Methods for the concrete class this concern is attached too, ways to find or create or just find the
|
29
|
+
# associated server.
|
30
|
+
#
|
31
|
+
module ClassMethods
|
32
|
+
#
|
33
|
+
# Find a record for this server
|
34
|
+
#
|
35
|
+
def find_or_create_server
|
36
|
+
find_or_create_by!(host_name: Socket.gethostname, pid: Process.pid)
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Find a worker, return nil if not found
|
41
|
+
#
|
42
|
+
def find_server
|
43
|
+
find_by(host_name: Socket.gethostname, pid: Process.pid)
|
44
|
+
rescue StandardError
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Perform a check in for the server
|
51
|
+
#
|
52
|
+
def check_in
|
53
|
+
set(last_check_in_at: Time.now.utc)
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Stop the worker
|
58
|
+
#
|
59
|
+
def stop
|
60
|
+
set(running: false, last_check_in_at: Time.now.utc)
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Start the worker
|
65
|
+
#
|
66
|
+
def start
|
67
|
+
set(running: true, last_check_in_at: Time.now.utc)
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Slack Configuration to be used inside of SystemConfiguration
|
5
|
+
#
|
6
|
+
module SlackConfiguration
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :slack_api_url, type: String
|
15
|
+
field :slack_support_channel, type: String, default: 'support'
|
16
|
+
field :slack_sales_channel, type: String, default: 'sales'
|
17
|
+
field :slack_notification_ttl, type: Integer, default: 5
|
18
|
+
#
|
19
|
+
# Validations
|
20
|
+
#
|
21
|
+
validates :slack_api_url, url: true, allow_blank: true
|
22
|
+
validates :slack_support_channel, presence: true
|
23
|
+
validates :slack_sales_channel, presence: true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Determine if Slack is configured
|
29
|
+
#
|
30
|
+
# Examples
|
31
|
+
#
|
32
|
+
# slack_configured??
|
33
|
+
# # => true || false
|
34
|
+
#
|
35
|
+
def slack_configured?
|
36
|
+
[slack_api_url.present?, slack_support_channel.present?, slack_sales_channel.present?].all?
|
37
|
+
end
|
38
|
+
end
|
@@ -42,9 +42,12 @@ module StandardModel
|
|
42
42
|
# Used by calling 'model.without_callback(*.args, &block) do'
|
43
43
|
def without_callback(*args, &_block)
|
44
44
|
skip_callback(*args)
|
45
|
-
yield
|
46
|
-
ensure
|
45
|
+
block_result = yield
|
47
46
|
set_callback(*args)
|
47
|
+
block_result
|
48
|
+
rescue StandardError
|
49
|
+
set_callback(*args)
|
50
|
+
nil
|
48
51
|
end
|
49
52
|
|
50
53
|
#
|
@@ -66,7 +69,7 @@ module StandardModel
|
|
66
69
|
names = field_names(filter_names)
|
67
70
|
names += associations if include_relationships
|
68
71
|
names.delete_if { |name| filter_names.include?(name) }
|
69
|
-
rescue StandardError
|
72
|
+
rescue StandardError => error
|
70
73
|
attribute_names.delete_if { |name| filter_names.include?(name) }
|
71
74
|
end
|
72
75
|
|
@@ -84,12 +87,8 @@ module StandardModel
|
|
84
87
|
#
|
85
88
|
def many_to_many_associations
|
86
89
|
associations = []
|
87
|
-
reflect_on_all_associations.each do |association|
|
88
|
-
|
89
|
-
next unless association.relation == Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy
|
90
|
-
else
|
91
|
-
next unless association.macro == :has_and_belongs_to_many
|
92
|
-
end
|
90
|
+
reflect_on_all_associations(:has_and_belongs_to_many).each do |association|
|
91
|
+
next unless association.relation == Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy
|
93
92
|
|
94
93
|
associations << { association.key => [] }
|
95
94
|
end
|