web47core 2.0.0 → 2.2.17
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 +19 -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/controllers/concerns/core_system_configuration_controller.rb +16 -5
- 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_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 +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 +36 -9
- metadata +117 -69
|
@@ -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: 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,65 @@
|
|
|
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_secret_access_key]
|
|
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
|
+
|
|
42
|
+
#
|
|
43
|
+
# AWS client.
|
|
44
|
+
#
|
|
45
|
+
def aws_ec2_client
|
|
46
|
+
return nil unless aws_configured?
|
|
47
|
+
|
|
48
|
+
@aws_ec2_client ||= Aws::EC2::Client.new(region: aws_region,
|
|
49
|
+
credentials: Aws::Credentials.new(aws_access_key_id,
|
|
50
|
+
aws_secret_access_key))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# S3 Client
|
|
55
|
+
#
|
|
56
|
+
def aws_s3_client
|
|
57
|
+
return nil unless aws_configured?
|
|
58
|
+
|
|
59
|
+
# We want this to remake itself each time because it is possible that the
|
|
60
|
+
# => user would change the access keys in between actions. Huh?
|
|
61
|
+
@aws_s3_client ||= Aws::S3::Client.new(region: aws_region,
|
|
62
|
+
access_key_id: aws_access_key_id,
|
|
63
|
+
secret_access_key: aws_secret_access_key)
|
|
64
|
+
end
|
|
65
|
+
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: 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,22 +1,24 @@
|
|
|
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
|
#
|
|
@@ -28,79 +30,31 @@ module CoreSystemConfiguration
|
|
|
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
|
#
|
|
@@ -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: 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
|
|
@@ -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
|
#
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Google SSO Configuration
|
|
5
|
+
#
|
|
6
|
+
module GoogleSsoConfiguration
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
def self.included(base)
|
|
10
|
+
base.class_eval do
|
|
11
|
+
#
|
|
12
|
+
# Fields
|
|
13
|
+
#
|
|
14
|
+
field :google_client_id, type: String
|
|
15
|
+
field :google_client_secret, 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[google_client_secret]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Determine if AWS is configured
|
|
28
|
+
#
|
|
29
|
+
def google_sso_configured?
|
|
30
|
+
google_client_id.present? && google_client_secret.present?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -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: 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
|