web47core 0.6.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 030670e1f995d60e8bf25b1fb67c9bd91a628e859225114fcfe6203f3c77e818
4
- data.tar.gz: 7db5d7cbaa718e3a296b209bf4c5e3b943441958c0019601ec031972803f6a09
3
+ metadata.gz: 8717398ffc274873a8057965f099744e56c95730a3b06dbf465b2ae56bb48a28
4
+ data.tar.gz: 3a519e7c3fd207057c8912c62ccb1e249fd268886bb82f6b431f4c7f88851109
5
5
  SHA512:
6
- metadata.gz: d9dedd01621102e871fd5f6f19b99f46ff331788d1feba24095daf10f023c058ed61a1b7cd654e8d965c478954e41e3e53ee2c39e33efc3f46f3f4d36233e038
7
- data.tar.gz: 1e77420c64920f5ffde02efa94def8a5d57d3832ebbff25177b80d9253949fbd26049b6e95fc952e7b5da415d9ab33d835e8e29f8032492dc888696134c806fc
6
+ metadata.gz: e9d493aeb49b89723db88f171fb8efb2d79ba8d91b3e77dbcc82cec171bca779accc0eb4a7dfb03aeef539436ec338b04f2ab79b5ca476cba2c7a2f043d8252f
7
+ data.tar.gz: 4e533fd3a6db8add02c7cfd40c3d5bce6512bec4656bd6f7a8eced741f8dae3a1ba030a6795feda080589540478b231e8670eff5d789ff0fc3c806262dacc743
data/README.md CHANGED
@@ -232,3 +232,7 @@ end
232
232
  #### ~/bin Directory
233
233
 
234
234
  Remove the delayed_job, delayed_job.sh and cron_server.sh files
235
+
236
+ #### Notification Templates
237
+
238
+ Move any notification templates from `~/app/assets/templates` to `~/lib/templates`
@@ -60,15 +60,16 @@ module CoreHelper
60
60
  # 3. Length 5-10 only show the first and last character
61
61
  # 4. Otherwise show the first and last three characters
62
62
  def mask_value(value, default: '************')
63
- return default if value.blank?
63
+ return default if value.blank? || !value.respond_to?(:to_s)
64
64
 
65
- case value.length
65
+ string_value = value.to_s
66
+ case string_value.length
66
67
  when 1..4
67
- "#{value.first}***********"
68
+ "#{string_value.first}***********"
68
69
  when 5..10
69
- "#{value.first}**********#{value.last}"
70
+ "#{string_value.first}**********#{string_value.last}"
70
71
  else
71
- "#{value[0..2]}**********#{value[-3..-1]}"
72
+ "#{string_value[0..2]}**********#{string_value[-3..-1]}"
72
73
  end
73
74
  end
74
75
 
@@ -0,0 +1 @@
1
+ =render '/delayed_jobs/index'
@@ -0,0 +1 @@
1
+ =render '/delayed_jobs/show'
@@ -1,5 +1 @@
1
- - title t('.title', name: SystemConfiguration.environment.titleize)
2
- .container
3
- %form{action: stack_system_configuration_path, method: :post}
4
- = render '/system_configurations/form', system_configuration: @system_configuration
5
- = render '/common/form_actions', form_cancel_path: admin_system_configuration_path
1
+ = render '/system_configurations/edit'
@@ -1,3 +1 @@
1
- - title t('.title', name: SystemConfiguration.environment.titleize)
2
- = edit_class_link_tag(SystemConfiguration, edit_stack_system_configuration_path)
3
- = render '/system_configurations/table'
1
+ = render '/system_configurations/show'
@@ -4,7 +4,26 @@
4
4
  # Base application job that all jobs extend from
5
5
  #
6
6
  class ApplicationJob < ActiveJob::Base
7
+ include ActionView::Helpers::NumberHelper
8
+ include ActionView::Helpers::TextHelper
7
9
  include App47Logger
10
+ attr_accessor :payload, :started_at
11
+
12
+ #
13
+ # Standard approach to running jobs
14
+ #
15
+ def perform(payload = {})
16
+ Rails.cache.reconnect
17
+ @started_at = Time.now.utc
18
+ @payload = payload
19
+ parse_payload
20
+ execute
21
+ rescue StandardError => error
22
+ log_error "Failed to execute job: #{self.inspect}", error
23
+ raise error
24
+ ensure
25
+ GC.start
26
+ end
8
27
 
9
28
  #
10
29
  # If this job should run in this current environment, defaults to true
@@ -20,4 +39,97 @@ class ApplicationJob < ActiveJob::Base
20
39
  my_environments = valid_environments
21
40
  (my_environments.empty? || my_environments.include?(Rails.env))
22
41
  end
42
+
43
+ #
44
+ # Internal: Parse the payload
45
+ #
46
+ # payload - The payload from the class attribute
47
+ #
48
+ # Examples
49
+ #
50
+ # parse_payload
51
+ #
52
+ # Assigns the class attributes from the payload
53
+ #
54
+ def parse_payload
55
+ attributes = payload.is_a?(Hash) ? payload : JSON.parse(payload)
56
+ # Set the values contained in the payload
57
+ attributes.each_pair do |key, value|
58
+ method = "#{key}=".to_sym
59
+ send(method, value) if respond_to?(method)
60
+ end
61
+ end
62
+
63
+ #
64
+ # Public: Determine the duration of the process, only reporting on the values that are
65
+ # greater than zero.
66
+ #
67
+ # Examples
68
+ #
69
+ # duration
70
+ # # => '1 day 1 hour 32 minutes 10 seconds'
71
+ # # => '1 hour 32 minutes 10 seconds'
72
+ # # => '32 minutes 10 seconds'
73
+ # # => '10 seconds'
74
+ #
75
+ # Returns the duration up until this point in time.
76
+ #
77
+ def duration
78
+ start_time = started_at.is_a?(String) ? Time.parse(started_at) : started_at
79
+ minutes, seconds = split_duration(Time.zone.now - start_time)
80
+ hours, minutes = split_duration minutes
81
+ days, hours = split_duration hours, 24
82
+ report_duration(days, hours, minutes, seconds)
83
+ end
84
+
85
+ private
86
+
87
+ #
88
+ # Internal: Take the current value and split using the split value, return the dividend and modulus
89
+ #
90
+ # value - The value to split
91
+ # split - The split value to use
92
+ #
93
+ # Examples
94
+ #
95
+ # split_duration( 120 )
96
+ # # => [2, 0]
97
+ # split_duration( 125 )
98
+ # # => [2, 5]
99
+ # split_duration( 125 )
100
+ # # => [2, 5]
101
+ # split_duration( 48, 24 )
102
+ # # => [2, 0]
103
+ #
104
+ # Returns an arround with the first value as the dividend and the second as the modulus
105
+ #
106
+ def split_duration(value, split = 60)
107
+ [(value / split).to_i, (value % split).to_i]
108
+ end
109
+
110
+ #
111
+ # Internal: Put together the descriptive text of the duration.
112
+ #
113
+ # days - The number of days
114
+ # hours - The number of hours
115
+ # minutes - The number of minutes
116
+ # seconds - The number of seconds
117
+ #
118
+ # Examples
119
+ #
120
+ # report_duration(0, 0, 10, 1)
121
+ # # => "10 minutes 1 second"
122
+ # report_duration(1, 0, 10, 1)
123
+ # # => "1 day 0 hours 10 minutes 1 second"
124
+ #
125
+ # Returns the duplicated String.
126
+ #
127
+ def report_duration(days, hours, minutes, seconds)
128
+ dur = []
129
+ dur << pluralize(days, 'day') if days.positive?
130
+ dur << pluralize(hours, 'hour') if hours.positive? || days.positive?
131
+ dur << pluralize(minutes, 'minute') if minutes.positive? || hours.positive? || days.positive?
132
+ dur << pluralize(seconds, 'second')
133
+ dur.join(' ')
134
+ end
23
135
  end
@@ -18,8 +18,7 @@ module Cron
18
18
  #
19
19
  # Cycle through all configuration keys
20
20
  #
21
- def perform
22
- Rails.cache.reconnect
21
+ def execute
23
22
  RestClient.get(switchboard_url,
24
23
  ACCESS_TOKEN: SystemConfiguration.switchboard_stack_api_token,
25
24
  content_type: 'application/json') do |response, _request, _result, &block|
@@ -18,7 +18,7 @@ module Cron
18
18
  #
19
19
  # Cycle through the collection and perform an upsert on it
20
20
  #
21
- def perform
21
+ def execute
22
22
  Web47core::Config.switchboard_able_models.each { |model| model.each(&:switchboard_upsert) }
23
23
  end
24
24
  end
@@ -9,8 +9,7 @@ module Cron
9
9
  #
10
10
  # Fetch each item and delete it if hasn't been updated in 30 days
11
11
  #
12
- def perform
13
- # Rails.cache.reconnect
12
+ def execute
14
13
  count = 0
15
14
  total = collection.count
16
15
  while count <= total
@@ -20,5 +20,25 @@ module Cron
20
20
  def collection
21
21
  Notification.all
22
22
  end
23
+
24
+ #
25
+ # Test if this should be archived
26
+ #
27
+ def archive?(item)
28
+ time = if item.is_a?(EmailNotification) && template?(item)
29
+ 5.years.ago.utc
30
+ else
31
+ allowed_time
32
+ end
33
+ item.updated_at < time
34
+ end
35
+
36
+ #
37
+ # Determine if the notification has a template associated with it
38
+ #
39
+ def template?(item)
40
+ item.notification_template.present? ||
41
+ item[:notification_template_id].present? && Template.where(_id: item[:notification_template_id]).present?
42
+ end
23
43
  end
24
44
  end
@@ -20,7 +20,7 @@ class AuditLog
20
20
  #
21
21
  # Validations
22
22
  #
23
- validates :action, inclusion: { in: ALL_ACTIONS }
23
+ # validates :action, inclusion: { in: ALL_ACTIONS }
24
24
 
25
25
  def self.sort_order
26
26
  [:created_at, -1]
@@ -39,4 +39,18 @@ module CoreAccount
39
39
  def fetch_smtp_configuration
40
40
  smtp_configuration || build_smtp_configuration
41
41
  end
42
+
43
+ #
44
+ # return the email notifications templates, these are custom notifications sent by an admin.
45
+ #
46
+ def email_notification_templates
47
+ templates.where(_type: 'EmailNotificationTemplate')
48
+ end
49
+
50
+ #
51
+ # return the email templates, these are email templates for actions in the system
52
+ #
53
+ def email_templates
54
+ templates.where(_type: 'EmailTemplate')
55
+ end
42
56
  end
@@ -16,6 +16,7 @@ module CoreSystemConfiguration
16
16
  #
17
17
  def self.included(base)
18
18
  base.class_eval do
19
+ attr_accessor :configuration
19
20
  #
20
21
  # Fields
21
22
  #
@@ -73,27 +74,12 @@ module CoreSystemConfiguration
73
74
  end
74
75
 
75
76
  module ClassMethods
76
- #
77
- # Fetch the system configuration based on environment name. First try the rails cache
78
- # if not there, then go to the database.
79
- #
80
- # Also, if an argument error is thrown, then just fetch from the database.
81
- #
82
77
  def configuration
83
- cache_key = "SystemConfiguration::#{Rails.env}"
84
-
85
- begin
86
- config = Rails.cache.fetch(cache_key, expires_in: 90.seconds) do
87
- SystemConfiguration.find_by(environment: Rails.env)
88
- end
89
- rescue StandardError
90
- # This seems to happen in testing relative to Country, when it does, remove
91
- # ourselves from the cache and return the DB entry.
92
- Rails.cache.delete cache_key
93
- config = SystemConfiguration.find_or_create_by!(environment: Rails.env)
94
- end
78
+ @configuration ||= SystemConfiguration.find_or_create_by!(environment: Rails.env)
79
+ end
95
80
 
96
- config.nil? ? SystemConfiguration.create(environment: Rails.env) : config
81
+ def reset
82
+ @configuration = nil
97
83
  end
98
84
 
99
85
  def smtp_configuration
@@ -110,19 +96,21 @@ module CoreSystemConfiguration
110
96
  #
111
97
  # NOTE: Currently ignored Codacy issue: When using 'method_missing', fall back on 'super'
112
98
  #
113
- # rubocop:disable Style/MethodMissingSuper
114
99
  def method_missing(method, *args, &_block)
115
- configuration.send method, *args
100
+ if configuration.respond_to?(method)
101
+ configuration.send(method, *args)
102
+ else
103
+ super
104
+ end
116
105
  end
117
106
 
118
- def respond_to?(method_name, _include_private = false)
119
- SystemConfiguration.fields.include?(method_name)
107
+ def respond_to?(method_name, include_private = false)
108
+ configuration.respond_to?(method_name, include_private) || super
120
109
  end
121
110
 
122
- def respond_to_missing?(method_name, _include_private = false)
123
- SystemConfiguration.fields.include?(method_name)
111
+ def respond_to_missing?(method_name, include_private = false)
112
+ configuration.respond_to?(method_name, include_private) || super
124
113
  end
125
- # rubocop:enable Style/MethodMissingSuper
126
114
  end
127
115
 
128
116
  #
@@ -147,7 +135,7 @@ module CoreSystemConfiguration
147
135
  #
148
136
  # Determine if mailgun is configured
149
137
  #
150
- def mailgun_configured?
138
+ def mail_gun_configured?
151
139
  smtp_configured? && mailgun_api_key.present?
152
140
  end
153
141
 
@@ -203,7 +191,7 @@ module CoreSystemConfiguration
203
191
  config = SystemConfiguration.configuration
204
192
  path = if config.zendesk_configured? && user.present?
205
193
  time_now = Time.now.to_i
206
- jti = "#{time_now}/#{rand(36**64).to_s(36)}"
194
+ jti = "#{time_now}/#{rand(36 ** 64).to_s(36)}"
207
195
  payload = { jwt: JWT.encode({ iat: time_now, # Seconds since epoch, determine when this token is stale
208
196
  jti: jti, # Unique token identifier, helps prevent replay attacks
209
197
  name: user.name,
@@ -262,12 +250,12 @@ module CoreSystemConfiguration
262
250
  slack_api_url.present?
263
251
  end
264
252
 
265
- private
253
+ # private
266
254
 
267
255
  #
268
256
  # Clear the cache when the object is saved
269
257
  #
270
258
  def clear_cache
271
- Rails.cache.delete "SystemConfiguration::#{Rails.env}"
259
+ SystemConfiguration.reset
272
260
  end
273
261
  end
@@ -62,7 +62,7 @@ module EmailAble
62
62
  # Reset the bounced email
63
63
  #
64
64
  def reset_bounce_status
65
- return unless SystemConfiguration.mailgun_configured? && email_bounced?
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)}"
68
68
  RestClient.delete(reset_url, user: 'api', password: SystemConfiguration.mailgun_api_key)
@@ -15,16 +15,16 @@ module StandardModel
15
15
  #
16
16
  # Fields
17
17
  #
18
- field :last_modified_by_email
19
- field :last_modified_by_name
20
- field :created_by_email
21
- field :created_by_name
18
+ field :last_modified_by_email, type: String
19
+ field :last_modified_by_name, type: String
20
+ field :created_by_email, type: String
21
+ field :created_by_name, type: String
22
22
  #
23
23
  # Relationships
24
24
  #
25
- belongs_to :last_modified_by, class_name: 'User', optional: true
26
- belongs_to :created_by, class_name: 'User', optional: true
27
- has_many Web47core::Config.user_audit_model_log_symbol, dependent: :nullify
25
+ belongs_to :last_modified_by, class_name: Web47core::Config.audit_model_class_name, optional: true
26
+ belongs_to :created_by, class_name: Web47core::Config.audit_model_class_name, optional: true
27
+ has_many Web47core::Config.audit_model_log_symbol, dependent: :nullify, inverse_of: :model
28
28
  #
29
29
  # Callbacks
30
30
  #
@@ -42,9 +42,9 @@ 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
- result = yield
45
+ yield
46
+ ensure
46
47
  set_callback(*args)
47
- result
48
48
  end
49
49
 
50
50
  #
@@ -60,10 +60,7 @@ module StandardModel
60
60
  def allowed_param_names(filter_names = [])
61
61
  # Always filter out the mongoid reserved items
62
62
  filter_names += %w[created_at updated_at _type _id]
63
- associations = all_associations
64
- # filter out the relationship names so we don't have dups
65
- associations.each { |association| filter_names << association.keys.first }
66
- (field_names + associations).delete_if { |name| filter_names.include?(name) }
63
+ field_names(filter_names)
67
64
  rescue StandardError
68
65
  attribute_names.delete_if { |name| filter_names.include?(name) }
69
66
  end
@@ -72,38 +69,19 @@ module StandardModel
72
69
  # allow the model to filter out a name if they want to, meaning the model
73
70
  # can return a subset of attribute names
74
71
  #
75
- def field_names
76
- attribute_names
77
- end
78
-
79
- #
80
- # gather up the collections we care about and return them. For now, the
81
- # many to many associations are the ones that need some extra help.
82
- #
83
- def all_associations
84
- many_to_many_associations
85
- end
86
-
87
- #
88
- # Return a collection of many to many assocations. We basically
89
- # need to turn the current value returned by attribute names
90
- #
91
- # relationship_ids
92
- #
93
- # to
94
- #
95
- # { relationship_ids => [] }
96
- #
97
- # Telling the permit command to accept the value as an array of items.
98
- #
99
- def many_to_many_associations
100
- associations = []
101
- reflect_on_all_associations.each do |association|
102
- next unless association.macro == :has_and_belongs_to_many
103
-
104
- associations << { association.key => [] }
105
- end
106
- associations
72
+ def field_names(filter_names)
73
+ fields.collect do |field|
74
+ next if filter_names.include?(field[0])
75
+
76
+ case field[1].options[:type].to_s
77
+ when 'Hash'
78
+ { field[0] => {} }
79
+ when 'Array'
80
+ { field[0] => [] }
81
+ else
82
+ field[0]
83
+ end
84
+ end.compact
107
85
  end
108
86
 
109
87
  #
@@ -142,10 +120,10 @@ module StandardModel
142
120
  # Log the audit record
143
121
  #
144
122
  def log_change(user, model, changes)
145
- Web47core::Config.user_audit_model_log_class.create!(Web47core::Config.user_audit_model => user,
146
- model: model,
147
- action: model.audit_action,
148
- changed_values: App47Logger.clean_params(changes).to_json)
123
+ Web47core::Config.audit_model_log_class.create!(Web47core::Config.audit_model => user,
124
+ model: model,
125
+ action: model.audit_action,
126
+ changed_values: App47Logger.clean_params(changes).to_json)
149
127
  end
150
128
  end
151
129
 
@@ -196,10 +174,10 @@ module StandardModel
196
174
  # record a change for the object instance
197
175
  #
198
176
  def log_change(user, changes, action)
199
- Web47core::Config.user_audit_model_log_class.create!(Web47core::Config.user_audit_model => user,
200
- model: self,
201
- action: action,
202
- changed_values: App47Logger.clean_params(changes).to_json)
177
+ Web47core::Config.audit_model_log_class.create!(Web47core::Config.audit_model => user,
178
+ model: self,
179
+ action: action,
180
+ changed_values: App47Logger.clean_params(changes).to_json)
203
181
  end
204
182
 
205
183
  def audit_action
@@ -300,10 +278,10 @@ module StandardModel
300
278
  # Log the deletion, capturing the current values of the record before it is removed from the system
301
279
  #
302
280
  def log_deletion(user, model)
303
- Web47core::Config.user_audit_model_log_class.create!(Web47core::Config.user_audit_model => user,
304
- model: model,
305
- action: AuditLog::DELETE_ACTION,
306
- changed_values: App47Logger.clean_params(attributes).to_json)
281
+ Web47core::Config.audit_model_log_class.create!(Web47core::Config.audit_model => user,
282
+ model: model,
283
+ action: AuditLog::DELETE_ACTION,
284
+ changed_values: App47Logger.clean_params(attributes).to_json)
307
285
  end
308
286
 
309
287
  def capture_user_info
@@ -9,8 +9,7 @@ module SwitchboardAble
9
9
  def self.included(base)
10
10
  base.class_eval do
11
11
  field :switchboard_id, type: String
12
- after_create :switchboard_upsert
13
- # after_update :switchboard_upsert
12
+ after_save :switchboard_upsert
14
13
  before_destroy :switchboard_delete
15
14
  end
16
15
  end
@@ -55,13 +54,12 @@ module SwitchboardAble
55
54
  def switchboard_delete
56
55
  return unless SystemConfiguration.switchboard_configured? && switchboard_id.present?
57
56
 
58
- RestClient.delete(switchboard_url, ACCESS_TOKEN: sw_api_token) do |response, _request, _result, &block|
57
+ RestClient.delete(switchboard_url, ACCESS_TOKEN: sw_api_token) do |response, _request, _result|
59
58
  case response.code
60
59
  when 200
61
60
  App47Logger.log_debug "Switchboard deleted #{inspect}"
62
61
  else
63
62
  App47Logger.log_error "Unable to delete the switchboard object #{inspect}, #{response.inspect}"
64
- response.return!(&block)
65
63
  end
66
64
  end
67
65
  end
@@ -231,23 +231,17 @@ class EmailNotification < Notification
231
231
  end
232
232
 
233
233
  def subject_from_template(template_name, locals)
234
- subject = account_subject_template(template_name) ||
235
- default_subject_template(template_name) ||
236
- template_from_file(template_name, prefix: 'subject')
237
- return subject_from_liquid_text(subject, locals) if subject.present?
238
-
239
- subject = template_from_file(template_name, format: 'haml', prefix: 'subject')
240
- subject_from_haml_text(subject, locals) if subject.present?
234
+ subject = account_subject_template(template_name) || Template.from_file(template_name, prefix: 'subject')
235
+ if subject.present?
236
+ subject_from_liquid_text(subject, locals)
237
+ else
238
+ subject = Template.from_file(template_name, format: 'haml', prefix: 'subject')
239
+ subject.present? ? subject_from_haml_text(subject, locals) : nil
240
+ end
241
241
  end
242
242
 
243
243
  def account_subject_template(template_name)
244
- account.templates.emails.find_by(name: template_name.to_s).subject
245
- rescue StandardError
246
- nil
247
- end
248
-
249
- def default_subject_template(template_name)
250
- EmailTemplate.where(account: nil, name: template_name.to_s).template
244
+ account.email_templates.find_by(name: template_name.to_s).subject
251
245
  rescue StandardError
252
246
  nil
253
247
  end
@@ -7,7 +7,37 @@ class EmailTemplate < Template
7
7
  #
8
8
  field :subject, type: String
9
9
  #
10
+ # Callbacks
11
+ #
12
+ before_save :htmlize_template
13
+ #
10
14
  # Validations
11
15
  #
12
16
  validates :subject, presence: true
17
+
18
+ #
19
+ # Make sure the template is wrapped in html
20
+ def htmlize_template
21
+ if template.present? && !template.strip.start_with?("<")
22
+ self.template = "<body><pre>#{template}</pre></body>"
23
+ end
24
+ end
25
+
26
+ def valid_liquid_template
27
+ super && Liquid::Template.parse(self.subject).nil?
28
+ rescue Exception => error
29
+ self.errors.add(:subject, "Invalid liquid text in subject: #{error.message}")
30
+ false
31
+ end
32
+
33
+ #
34
+ # Copy the default from disk
35
+ #
36
+ def self.copy_default(name)
37
+ template = EmailTemplate.new
38
+ template.name = name
39
+ template.template = from_file name
40
+ template.subject = from_file name, prefix: 'subject'
41
+ template
42
+ end
13
43
  end
@@ -158,7 +158,7 @@ class Notification
158
158
  # If the account does exists or the template in the account does exist, we catch the error and return nil
159
159
  #
160
160
  def account_message_template(template_name)
161
- account.templates.find_by(name: template_name.to_s, _type: "Account#{delivery_channel.humanize}Template").template
161
+ account.templates.find_by(name: template_name.to_s, _type: "#{delivery_channel.humanize}Template").template
162
162
  rescue StandardError
163
163
  nil
164
164
  end
@@ -172,20 +172,6 @@ class Notification
172
172
  nil
173
173
  end
174
174
 
175
- #
176
- # Retrieve the template out of the project
177
- #
178
- def template_from_file(template_name, format: 'liquid', prefix: nil)
179
- file_name = [template_name, prefix, format].compact.join('.')
180
- if File.exist?(Rails.root.join('lib', 'templates', delivery_channel, file_name))
181
- File.open(Rails.root.join('lib', 'templates', delivery_channel, file_name))
182
- else
183
- File.read(File.join(__dir__, '../../lib', 'templates', delivery_channel, file_name))
184
- end.read
185
- rescue StandardError
186
- nil
187
- end
188
-
189
175
  #
190
176
  # Default delivery channel is email, override for sms, SMTP or other channels
191
177
  #
@@ -194,17 +180,20 @@ class Notification
194
180
  end
195
181
 
196
182
  def message_from_template(template_name, locals)
197
- template = account_message_template(template_name) || template_from_file(template_name)
198
- return message_from_liquid_text(template, locals) if template.present?
199
-
200
- template = template_from_file(template_name, format: 'haml')
201
- message_from_haml_text(template, locals) if template.present?
183
+ template = account_message_template(template_name) ||
184
+ Template.from_file(template_name, delivery_channel: delivery_channel)
185
+ if template.present?
186
+ message_from_liquid_text(template, locals)
187
+ else
188
+ template = Template.from_file(template_name, format: 'haml', delivery_channel: delivery_channel)
189
+ template.present? ? message_from_haml_text(template, locals) : nil
190
+ end
202
191
  end
203
192
 
204
193
  def message_from_haml_text(haml_text, locals)
205
194
  locals[:base_url] = SystemConfiguration.base_url
206
195
  engine = Haml::Engine.new(haml_text)
207
- self.message = engine.render(Object.new, stringify_all(locals))
196
+ self.message = engine.render(Object.new, locals)
208
197
  end
209
198
 
210
199
  def message_from_haml_file(file_name, locals)
@@ -18,4 +18,31 @@ class Template
18
18
  validates :name, uniqueness: { scope: :account_id }
19
19
  validates :name, presence: true
20
20
  validates :template, presence: true
21
+ validate :valid_liquid_template
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
+ #
36
+ # Retrieve the template out of the project
37
+ #
38
+ def self.from_file(template_name, format: 'liquid', prefix: nil, delivery_channel: 'email')
39
+ file_name = [template_name, prefix, format].compact.join('.')
40
+ if File.exist?(Rails.root.join('lib/templates', delivery_channel, file_name))
41
+ File.open(Rails.root.join('lib/templates', delivery_channel, file_name))
42
+ else
43
+ File.read(File.join(__dir__, '../../lib/templates', delivery_channel, file_name))
44
+ end.read
45
+ rescue StandardError
46
+ nil
47
+ end
21
48
  end
@@ -6,30 +6,34 @@ module Web47core
6
6
  #
7
7
  class Config
8
8
  include Singleton
9
- attr_accessor :email_able_models, :switchboard_able_models, :user_audit_model
9
+ attr_accessor :email_able_models, :switchboard_able_models, :audit_model
10
10
 
11
11
  def initialize
12
12
  @email_able_models = []
13
13
  @switchboard_able_models = []
14
- @user_audit_model = :user
14
+ @audit_model = :user
15
15
  end
16
16
 
17
17
  def self.reset
18
18
  instance.email_able_models = []
19
19
  instance.switchboard_able_models = []
20
- instance.user_audit_model = :user
20
+ instance.audit_model = :user
21
21
  end
22
22
 
23
- def self.user_audit_model_log_class
24
- user_audit_model_log_class_name.constantize
23
+ def self.audit_model_log_class
24
+ audit_model_log_class_name.constantize
25
25
  end
26
26
 
27
- def self.user_audit_model_log_class_name
28
- user_audit_model_log_symbol.camelize
27
+ def self.audit_model_log_class_name
28
+ audit_model_log_symbol.camelize
29
29
  end
30
30
 
31
- def self.user_audit_model_log_symbol
32
- "#{instance.user_audit_model}_model_audit_log"
31
+ def self.audit_model_log_symbol
32
+ "#{instance.audit_model}_model_audit_log"
33
+ end
34
+
35
+ def self.audit_model_class_name
36
+ instance.audit_model.to_s.camelize
33
37
  end
34
38
 
35
39
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Web47core
4
- VERSION = '0.6.3'
4
+ VERSION = '0.7.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web47core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Schroeder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-17 00:00:00.000000000 Z
11
+ date: 2020-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -583,6 +583,8 @@ files:
583
583
  - app/views/delayed_jobs/show.html.haml
584
584
  - app/views/stack/cron/edit.html.haml
585
585
  - app/views/stack/cron/index.html.haml
586
+ - app/views/stack/delayed_jobs/index.html.haml
587
+ - app/views/stack/delayed_jobs/show.html.haml
586
588
  - app/views/stack/system_configurations/edit.html.haml
587
589
  - app/views/stack/system_configurations/show.html.haml
588
590
  - app/views/status/index.html.haml