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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +111 -41
  3. data/app/controllers/status_controller.rb +15 -4
  4. data/app/helpers/core_form_helper.rb +6 -6
  5. data/app/helpers/core_helper.rb +1 -1
  6. data/app/helpers/core_link_helper.rb +47 -8
  7. data/app/helpers/core_nav_bar_helper.rb +5 -4
  8. data/app/helpers/core_table_helper.rb +80 -0
  9. data/app/helpers/model_modal_helper.rb +3 -3
  10. data/app/views/common/_create_actions.html.haml +12 -0
  11. data/app/views/common/_update_actions.html.haml +10 -0
  12. data/app/views/cron/_edit.html.haml +15 -17
  13. data/app/views/cron/_index.html.haml +74 -67
  14. data/app/views/delayed_job_metrics/_index.html.haml +27 -0
  15. data/app/views/delayed_job_metrics/index.html.haml +1 -0
  16. data/app/views/delayed_job_workers/_index.html.haml +27 -0
  17. data/app/views/delayed_job_workers/index.html.haml +1 -0
  18. data/app/views/delayed_jobs/_index.html.haml +47 -52
  19. data/app/views/delayed_jobs/_show.html.haml +15 -13
  20. data/app/views/system_configurations/_edit.html.haml +14 -9
  21. data/app/views/system_configurations/_show.html.haml +18 -12
  22. data/config/brakeman.ignore +26 -0
  23. data/config/brakeman.yml +2 -0
  24. data/config/locales/en.yml +21 -3
  25. data/lib/app/controllers/concerns/core_delayed_job_metrics_controller.rb +35 -0
  26. data/lib/app/controllers/concerns/core_delayed_job_workers_controller.rb +35 -0
  27. data/lib/app/controllers/concerns/core_delayed_jobs_controller.rb +2 -3
  28. data/lib/app/jobs/application_job.rb +0 -1
  29. data/lib/app/jobs/cron/command.rb +1 -4
  30. data/lib/app/jobs/cron/record_delayed_job_metrics.rb +25 -0
  31. data/lib/app/jobs/cron/restart_orphaned_delayed_jobs.rb +44 -0
  32. data/lib/app/jobs/cron/server.rb +32 -15
  33. data/lib/app/jobs/cron/switchboard_sync_configuration.rb +2 -0
  34. data/lib/app/jobs/cron/switchboard_sync_models.rb +2 -0
  35. data/lib/app/jobs/cron/tab.rb +1 -1
  36. data/lib/app/jobs/cron/trim_collection.rb +1 -1
  37. data/lib/app/jobs/cron/trim_command_jobs.rb +28 -0
  38. data/lib/app/jobs/cron/trim_delayed_job_metrics.rb +29 -0
  39. data/lib/app/jobs/cron/trim_delayed_job_workers.rb +39 -0
  40. data/lib/app/jobs/cron/trim_failed_delayed_jobs.rb +2 -0
  41. data/lib/app/models/api_token.rb +9 -0
  42. data/lib/app/models/command_job.rb +375 -0
  43. data/lib/app/models/command_job_log.rb +33 -0
  44. data/lib/app/models/concerns/api_tokenable.rb +38 -0
  45. data/lib/app/models/concerns/aws_configuration.rb +41 -0
  46. data/lib/app/models/concerns/cdn_url.rb +7 -0
  47. data/lib/app/models/concerns/core_smtp_configuration.rb +65 -0
  48. data/lib/app/models/concerns/core_system_configuration.rb +21 -204
  49. data/lib/app/models/concerns/delayed_job_configuration.rb +24 -0
  50. data/lib/app/models/concerns/email_able.rb +7 -3
  51. data/lib/app/models/concerns/search_able.rb +16 -0
  52. data/lib/app/models/concerns/server_process_able.rb +69 -0
  53. data/lib/app/models/concerns/slack_configuration.rb +38 -0
  54. data/lib/app/models/concerns/standard_model.rb +8 -9
  55. data/lib/app/models/concerns/switchboard_configuration.rb +43 -0
  56. data/lib/app/models/concerns/twilio_configuration.rb +37 -0
  57. data/lib/app/models/concerns/zendesk_configuration.rb +92 -0
  58. data/lib/app/models/{delayed_job.rb → delayed/backend/delayed_job.rb} +41 -0
  59. data/lib/app/models/delayed/jobs/metric.rb +61 -0
  60. data/lib/app/models/delayed/jobs/run.rb +40 -0
  61. data/lib/app/models/delayed/jobs/worker.rb +43 -0
  62. data/lib/app/models/delayed/plugins/time_keeper.rb +33 -0
  63. data/lib/app/models/delayed/worker.rb +24 -0
  64. data/lib/app/models/email_notification.rb +2 -1
  65. data/lib/app/models/email_template.rb +5 -6
  66. data/lib/app/models/notification.rb +12 -2
  67. data/lib/app/models/notification_template.rb +1 -1
  68. data/lib/app/models/sms_notification.rb +9 -6
  69. data/lib/app/models/smtp_configuration.rb +3 -3
  70. data/lib/app/models/template.rb +12 -12
  71. data/lib/web47core/version.rb +1 -1
  72. data/lib/web47core.rb +35 -9
  73. 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
- # Slack support
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, *args, &block)
61
+ def method_missing(method, ...)
108
62
  if configuration.respond_to?(method)
109
- configuration.send(method, *args, &block)
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
- set email_bounced_at: nil, email_bounce_reason: nil
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
- if Mongoid::Compatibility::Version.mongoid7_or_newer?
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