Class: Notification

Inherits:
Object
  • Object
show all
Includes:
SearchAble, 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 SearchAble

#after_search_text, #before_search_text, included, #method_missing, #respond_to?, #respond_to_missing?, #sort_fields, #update_search_and_sort_text, #update_text

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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class SearchAble

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



163
164
165
166
167
# File 'lib/app/models/notification.rb', line 163

def (template_name)
  .templates.find_by(name: template_name.to_s, _type: "#{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



172
173
174
175
176
# File 'lib/app/models/notification.rb', line 172

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)


68
69
70
# File 'lib/app/models/notification.rb', line 68

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

#deliver_messageObject



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

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



131
132
133
# File 'lib/app/models/notification.rb', line 131

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



181
182
183
# File 'lib/app/models/notification.rb', line 181

def delivery_channel
  DELIVERY_EMAIL
end

#finish_processing(processing_message = nil) ⇒ Object

Finish processing the notification successfully



103
104
105
106
107
108
109
110
# File 'lib/app/models/notification.rb', line 103

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

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



153
154
155
156
# File 'lib/app/models/notification.rb', line 153

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



202
203
204
# File 'lib/app/models/notification.rb', line 202

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



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

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, locals)
end

#message_from_liquid_text(liquid_text, locals) ⇒ Object



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

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

#message_from_template(template_name, locals) ⇒ Object



185
186
187
188
189
190
191
192
193
194
# File 'lib/app/models/notification.rb', line 185

def message_from_template(template_name, locals)
  template = (template_name) ||
    Template.from_file(template_name, delivery_channel: delivery_channel)
  if template.present?
    message_from_liquid_text(template, locals)
  else
    template = Template.from_file(template_name, format: 'haml', delivery_channel: delivery_channel)
    template.present? ? message_from_haml_text(template, locals) : nil
  end
end

#nameObject

Titleize the type of this notification as its name



242
243
244
245
246
# File 'lib/app/models/notification.rb', line 242

def name
  _type.titleize
rescue StandardError
  _type
end

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

Render the given liquid text



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

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



96
97
98
# File 'lib/app/models/notification.rb', line 96

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

#search_fieldsObject

Support search fields



251
252
253
# File 'lib/app/models/notification.rb', line 251

def search_fields
  %w[to state recipient_name]
end

#send_notificationObject

Send the notification



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

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)


75
76
77
# File 'lib/app/models/notification.rb', line 75

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

#start_processingObject

Start processing the notification



89
90
91
# File 'lib/app/models/notification.rb', line 89

def start_processing
  set state: STATE_PROCESSING
end

#stringify_all(obj) ⇒ Object

Convert all keys and values to strings for liquid sanity



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/app/models/notification.rb', line 221

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)


61
62
63
# File 'lib/app/models/notification.rb', line 61

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

#viewedObject

Mark this as viewed



82
83
84
# File 'lib/app/models/notification.rb', line 82

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