Class: Notification

Inherits:
Object
  • Object
show all
Includes:
StandardModel
Defined in:
lib/app/models/notification.rb

Overview

Base class for notification

Constant Summary collapse

STATE_INVALID =

Constants

'invalid'
STATE_NEW =
'new'
STATE_PROCESSED =
'processed'
STATE_PROCESSING =
'processing'
STATE_RESUBMITTED =
'resubmitted'
STATE_RETRYING =
'retrying'
STATE_SUBMITTED =
'submitted'
STATE_VIEWED =
'viewed'
ALL_STATES =
[STATE_INVALID,
STATE_NEW,
STATE_PROCESSED,
STATE_PROCESSING,
STATE_RESUBMITTED,
STATE_RETRYING,
STATE_SUBMITTED,
STATE_VIEWED].freeze
DELIVERY_EMAIL =

Channels

'email'
DELIVERY_SLACK =
'slack'
DELIVERY_SMS =
'sms'

Instance Method Summary collapse

Methods included from StandardModel

#audit_action, #auto_strip_attributes, #capture_user_info, #clear_cache, #created_by_display_name, #delete_and_log, #destroy_and_log, included, #last_modified_by_display_name, #log_change, #log_deletion, #remove_blank_secure_fields, #save_and_log, #save_and_log!, #secure_fields, #update, #update!, #update_and_log, #update_and_log!

Methods included from App47Logger

clean_params, #clean_params, delete_parameter_keys, #log_controller_error, log_debug, #log_debug, log_error, #log_error, log_exception, #log_message, log_message, #log_warn, log_warn, mask_parameter_keys, #update_flash_messages

Instance Method Details

#account_message_template(template_name) ⇒ Object

Retrieve the template from the account

If the account does exists or the template in the account does exist, we catch the error and return nil



160
161
162
163
164
# File 'lib/app/models/notification.rb', line 160

def (template_name)
  .templates.find_by(name: template_name.to_s, _type: "Account#{delivery_channel.humanize}Template").template
rescue StandardError
  nil
end

#default_message_template(template_name) ⇒ Object

Get the default template stored in the database that is not associated with an account



169
170
171
172
173
# File 'lib/app/models/notification.rb', line 169

def default_message_template(template_name)
  Template.find_by(account: nil, name: template_name.to_s).template
rescue StandardError
  nil
end

#deletable?Boolean

If this notification can be deleted, we don’t want to delete one that is currently being processed.

Returns:

  • (Boolean)


66
67
68
# File 'lib/app/models/notification.rb', line 66

def deletable?
  [STATE_PROCESSED, STATE_INVALID, STATE_NEW, STATE_VIEWED].include? state
end

#deliver_messageObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/app/models/notification.rb', line 132

def deliver_message
  start_processing
  deliver_message!
  finish_processing
rescue StandardError => error
  if retries > 10
    log_error "Unable to process notification id: #{id}, done retrying", error
    finish_processing "Failed final attempt: #{error.message}"
    notify_failure(error)
  else
    log_error "Unable to process notification id: #{id}, retrying!!", error
    retry_delivery("Failed attempt # #{retries}: #{error.message}")
    delay(run_at: 10.minutes.from_now).deliver
  end
end

#deliver_message!Object



128
129
130
# File 'lib/app/models/notification.rb', line 128

def deliver_message!
  raise 'Incomplete class, concrete implementation should implment #deliver_message!'
end

#delivery_channelObject

Default delivery channel is email, override for sms, SMTP or other channels



192
193
194
# File 'lib/app/models/notification.rb', line 192

def delivery_channel
  DELIVERY_EMAIL
end

#finish_processing(processing_message = nil) ⇒ Object

Finish processing the notification successfully



101
102
103
104
105
106
107
# File 'lib/app/models/notification.rb', line 101

def finish_processing(processing_message = nil)
  if processing_message.present?
    set state: STATE_INVALID, error_message: processing_message
  else
    set state: STATE_PROCESSED, error_message: ''
  end
end

#from_template(template_name, locals = {}) ⇒ Object



150
151
152
153
# File 'lib/app/models/notification.rb', line 150

def from_template(template_name, locals = {})
  locals[:base_url] = SystemConfiguration.base_url
  self.message = message_from_template(template_name, locals)
end

#message_from_haml_file(file_name, locals) ⇒ Object



210
211
212
# File 'lib/app/models/notification.rb', line 210

def message_from_haml_file(file_name, locals)
  message_from_haml_text(File.read(file_name), locals)
end

#message_from_haml_text(haml_text, locals) ⇒ Object



204
205
206
207
208
# File 'lib/app/models/notification.rb', line 204

def message_from_haml_text(haml_text, locals)
  locals[:base_url] = SystemConfiguration.base_url
  engine = Haml::Engine.new(haml_text)
  self.message = engine.render(Object.new, stringify_all(locals))
end

#message_from_liquid_text(liquid_text, locals) ⇒ Object



214
215
216
# File 'lib/app/models/notification.rb', line 214

def message_from_liquid_text(liquid_text, locals)
  self.message = render_liquid_text(liquid_text, locals)
end

#message_from_template(template_name, locals) ⇒ Object



196
197
198
199
200
201
202
# File 'lib/app/models/notification.rb', line 196

def message_from_template(template_name, locals)
  template = (template_name) || template_from_file(template_name)
  return message_from_liquid_text(template, locals) if template.present?

  template = template_from_file(template_name, format: 'haml')
  message_from_haml_text(template, locals) if template.present?
end

#render_liquid_text(liquid_text, locals = {}) ⇒ Object

Render the given liquid text



221
222
223
224
# File 'lib/app/models/notification.rb', line 221

def render_liquid_text(liquid_text, locals = {})
  locals[:base_url] = SystemConfiguration.base_url
  Liquid::Template.parse(liquid_text).render(stringify_all(locals))
end

#retry_delivery(message) ⇒ Object

Set to retrying



94
95
96
# File 'lib/app/models/notification.rb', line 94

def retry_delivery(message)
  set error_message: message, retries: retries + 1, state: STATE_RETRYING
end

#send_notificationObject

Send the notification



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/app/models/notification.rb', line 112

def send_notification
  if state.eql? STATE_NEW
    self.state = STATE_SUBMITTED
  else
    self.retries = 0
    self.state = STATE_RESUBMITTED
    self.error_message = 'Retrying'
  end

  begin
    deliver_message if save!
  rescue StandardError => error
    finish_processing error.message
  end
end

#sendable?Boolean

If this notification can be resent, we don’t want to resend one that is currently being processed.

Returns:

  • (Boolean)


73
74
75
# File 'lib/app/models/notification.rb', line 73

def sendable?
  [STATE_PROCESSED, STATE_INVALID, STATE_NEW, STATE_VIEWED].include? state
end

#start_processingObject

Start processing the notification



87
88
89
# File 'lib/app/models/notification.rb', line 87

def start_processing
  set state: STATE_PROCESSING
end

#stringify_all(obj) ⇒ Object

Convert all keys and values to strings for liquid sanity



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/app/models/notification.rb', line 229

def stringify_all(obj)
  case obj
  when Hash
    result = {}
    obj.each { |key, value| result[key.to_s] = stringify_all(value) }
  when Array
    result = []
    obj.each { |value| result << stringify_all(value) }
  when FalseClass
    result = false
  when TrueClass
    result = true
  else
    result = obj.to_s
  end
  result
end

#successful?Boolean

Was this notification successful sent

Returns:

  • (Boolean)


59
60
61
# File 'lib/app/models/notification.rb', line 59

def successful?
  [STATE_PROCESSED, STATE_VIEWED].include? state
end

#template_from_file(template_name, format: 'liquid', prefix: nil) ⇒ Object

Retrieve the template out of the project



178
179
180
181
182
183
184
185
186
187
# File 'lib/app/models/notification.rb', line 178

def template_from_file(template_name, format: 'liquid', prefix: nil)
  file_name = [template_name, prefix, format].compact.join('.')
  if File.exist?(Rails.root.join('lib', 'templates', delivery_channel, file_name))
    File.open(Rails.root.join('lib', 'templates', delivery_channel, file_name))
  else
    File.read(File.join(__dir__, '../../lib', 'templates', delivery_channel, file_name))
  end.read
rescue StandardError
  nil
end

#viewedObject

Mark this as viewed



80
81
82
# File 'lib/app/models/notification.rb', line 80

def viewed
  set(state: STATE_VIEWED, last_viewed_at: Time.now.utc, viewed_count: viewed_count + 1)
end