Class: Effective::Notification
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Effective::Notification
- Defined in:
- app/models/effective/notification.rb
Constant Summary collapse
- AUDIENCES =
[ ['Send to user or email from the report', 'report'], ['Send to specific addresses', 'emails'] ]
- SCHEDULE_TYPES =
[ ['On the first day they appear in the report and every x days thereafter', 'immediate'], ['When present in the report on the following dates', 'scheduled'] ]
- SCHEDULED_METHODS =
TODO: [‘Send once’, ‘Send daily’, ‘Send weekly’, ‘Send monthly’, ‘Send quarterly’, ‘Send yearly’, ‘Send now’]
[ ['The following dates...', 'dates'], ]
- CONTENT_TYPES =
['text/plain', 'text/html']
Instance Attribute Summary collapse
-
#current_resource ⇒ Object
Returns the value of attribute current_resource.
-
#current_user ⇒ Object
Returns the value of attribute current_user.
-
#view_context ⇒ Object
Returns the value of attribute view_context.
Instance Method Summary collapse
- #assign_renderer(view_context) ⇒ Object
-
#assigns_for(resource = nil) ⇒ Object
We pull the Assigns from 3 places: 1.
- #audience_emails ⇒ Object
- #audience_emails? ⇒ Boolean
- #audience_report? ⇒ Boolean
- #build_notification_log(resource: nil, skipped: false) ⇒ Object
- #disable! ⇒ Object
- #enable! ⇒ Object
-
#immediate? ⇒ Boolean
This operates on each row of the resource.
- #notifiable?(resource, date: nil) ⇒ Boolean
-
#notifiable_immediate?(resource:, date: nil) ⇒ Boolean
Consider the notification logs which track how many and how long ago this notification was sent It’s notifiable? when first time or if it’s been immediate_days since last notification.
- #notifiable_rows_count ⇒ Object
- #notifiable_scheduled?(date: nil) ⇒ Boolean
- #notifiable_tomorrow?(resource) ⇒ Boolean
- #notifiable_tomorrow_rows_count ⇒ Object
-
#notify!(force: false) ⇒ Object
The main function to send this thing.
-
#notify_by_resources!(force: false) ⇒ Object
Operates on every resource in the data source.
- #notify_by_schedule!(force: false) ⇒ Object
- #render_email(resource = nil) ⇒ Object
- #renderer ⇒ Object
- #report_variables ⇒ Object
- #rows_count ⇒ Object
- #schedule ⇒ Object
- #scheduled? ⇒ Boolean
- #scheduled_dates ⇒ Object
-
#scheduled_email? ⇒ Boolean
Only scheduled emails can have attached reports.
-
#send_now! ⇒ Object
Enqueues this notification to send right away.
-
#skip_once! ⇒ Object
Only applies to immedate? notifications Skips over one notification on the immediate notifications.
- #template_body ⇒ Object
- #template_subject ⇒ Object
- #to_s ⇒ Object
Instance Attribute Details
#current_resource ⇒ Object
Returns the value of attribute current_resource.
8 9 10 |
# File 'app/models/effective/notification.rb', line 8 def current_resource @current_resource end |
#current_user ⇒ Object
Returns the value of attribute current_user.
7 8 9 |
# File 'app/models/effective/notification.rb', line 7 def current_user @current_user end |
#view_context ⇒ Object
Returns the value of attribute view_context.
9 10 11 |
# File 'app/models/effective/notification.rb', line 9 def view_context @view_context end |
Instance Method Details
#assign_renderer(view_context) ⇒ Object
205 206 207 208 209 |
# File 'app/models/effective/notification.rb', line 205 def assign_renderer(view_context) raise('expected renderer to respond to') unless view_context.respond_to?(:root_url) assign_attributes(view_context: view_context) self end |
#assigns_for(resource = nil) ⇒ Object
We pull the Assigns from 3 places:
-
The report.report_columns
-
The class’s def reportable_view_assigns(view) method
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'app/models/effective/notification.rb', line 383 def assigns_for(resource = nil) return {} unless report.present? resource ||= report.reportable.new raise('expected an acts_as_reportable resource') unless resource.class.try(:acts_as_reportable?) report_assigns = Array(report.report_columns).inject({}) do |h, column| value = resource.send(column.name) h[column.name] = column.format(value); h end reportable_view_assigns = resource.reportable_view_assigns(renderer).deep_stringify_keys raise('expected notification assigns to return a Hash') unless reportable_view_assigns.kind_of?(Hash) # Merge all 3 report_assigns.merge(reportable_view_assigns) end |
#audience_emails ⇒ Object
185 186 187 |
# File 'app/models/effective/notification.rb', line 185 def audience_emails Array(self[:audience_emails]) - [nil, ''] end |
#audience_emails? ⇒ Boolean
171 172 173 |
# File 'app/models/effective/notification.rb', line 171 def audience_emails? audience == 'emails' end |
#audience_report? ⇒ Boolean
175 176 177 |
# File 'app/models/effective/notification.rb', line 175 def audience_report? audience == 'report' end |
#build_notification_log(resource: nil, skipped: false) ⇒ Object
401 402 403 404 405 406 407 408 |
# File 'app/models/effective/notification.rb', line 401 def build_notification_log(resource: nil, skipped: false) user = resource_user(resource) email = resource_email(resource) || user.try(:email) email ||= audience_emails_to_s if scheduled_email? notification_logs.build(email: email, report: report, resource: resource, user: user, skipped: skipped) end |
#disable! ⇒ Object
231 232 233 |
# File 'app/models/effective/notification.rb', line 231 def disable! update!(enabled: false) end |
#enable! ⇒ Object
227 228 229 |
# File 'app/models/effective/notification.rb', line 227 def enable! update!(enabled: true) end |
#immediate? ⇒ Boolean
This operates on each row of the resource. We track the number of notifications total to see if we should notify again or not
163 164 165 |
# File 'app/models/effective/notification.rb', line 163 def immediate? schedule_type == 'immediate' end |
#notifiable?(resource, date: nil) ⇒ Boolean
305 306 307 308 309 310 311 312 313 314 315 |
# File 'app/models/effective/notification.rb', line 305 def notifiable?(resource, date: nil) raise('expected an acts_as_reportable resource') unless resource.class.try(:acts_as_reportable?) if schedule_type == 'immediate' notifiable_immediate?(resource: resource, date: date) elsif schedule_type == 'scheduled' notifiable_scheduled?(date: date) else raise("unsupported schedule_type") end end |
#notifiable_immediate?(resource:, date: nil) ⇒ Boolean
Consider the notification logs which track how many and how long ago this notification was sent It’s notifiable? when first time or if it’s been immediate_days since last notification
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'app/models/effective/notification.rb', line 324 def notifiable_immediate?(resource:, date: nil) raise('expected an immediate? notification') unless immediate? email = resource_email(resource) || resource_user(resource).try(:email) raise("expected an email for #{report} #{report&.id} and #{resource} #{resource&.id}") unless email.present? logs = notification_logs.select { |log| log.email == email } if logs.count == 0 true # This is the first time. We should send. elsif logs.count < immediate_times # We still have to send it but consider dates. last_sent_days_ago = logs.map { |log| log.days_ago(date: date) }.min || 0 (last_sent_days_ago >= immediate_days) else false # We've already sent enough times end end |
#notifiable_rows_count ⇒ Object
219 220 221 |
# File 'app/models/effective/notification.rb', line 219 def notifiable_rows_count report.collection().select { |resource| notifiable?(resource) }.count if report end |
#notifiable_scheduled?(date: nil) ⇒ Boolean
343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'app/models/effective/notification.rb', line 343 def notifiable_scheduled?(date: nil) raise('expected a scheduled? notification') unless scheduled? date ||= Time.zone.now.beginning_of_day case scheduled_method when 'dates' scheduled_dates.find { |day| day == date.strftime('%F') }.present? else raise('unsupported scheduled_method') end end |
#notifiable_tomorrow?(resource) ⇒ Boolean
317 318 319 320 |
# File 'app/models/effective/notification.rb', line 317 def notifiable_tomorrow?(resource) date = Time.zone.now.beginning_of_day.advance(days: 1) notifiable?(resource, date: date) end |
#notifiable_tomorrow_rows_count ⇒ Object
223 224 225 |
# File 'app/models/effective/notification.rb', line 223 def notifiable_tomorrow_rows_count report.collection().select { |resource| notifiable_tomorrow?(resource) }.count if report end |
#notify!(force: false) ⇒ Object
The main function to send this thing
266 267 268 |
# File 'app/models/effective/notification.rb', line 266 def notify!(force: false) scheduled_email? ? notify_by_schedule!(force: force) : notify_by_resources!(force: force) end |
#notify_by_resources!(force: false) ⇒ Object
Operates on every resource in the data source. Sends one email for each row
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'app/models/effective/notification.rb', line 271 def notify_by_resources!(force: false) notified = 0 report.collection().find_each do |resource| next unless notifiable?(resource) || force print('.') # For logging assign_attributes(current_resource: resource) # Send the resource email build_notification_log(resource: resource).save! Effective::NotificationsMailer.notify_resource(self, resource).deliver_now notified += 1 GC.start if (notified % 250) == 0 end notified > 0 ? update!(last_notified_at: Time.zone.now, last_notified_count: notified) : touch end |
#notify_by_schedule!(force: false) ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 |
# File 'app/models/effective/notification.rb', line 293 def notify_by_schedule!(force: false) notified = 0 if notifiable_scheduled? || force build_notification_log(resource: nil).save! Effective::NotificationsMailer.notify(self).deliver_now notified += 1 end notified > 0 ? update!(last_notified_at: Time.zone.now, last_notified_count: notified) : touch end |
#render_email(resource = nil) ⇒ Object
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'app/models/effective/notification.rb', line 356 def render_email(resource = nil) raise('expected an acts_as_reportable resource') if resource.present? && !resource.class.try(:acts_as_reportable?) to = if audience == 'emails' audience_emails.presence elsif audience == 'report' resource_email(resource) || resource_user(resource).try(:email) end raise('expected a to email address') unless to.present? assigns = assigns_for(resource) { to: to, from: from, cc: cc.presence, bcc: bcc.presence, content_type: CONTENT_TYPES.first, subject: template_subject.render(assigns), body: template_body.render(assigns) }.compact end |
#renderer ⇒ Object
211 212 213 |
# File 'app/models/effective/notification.rb', line 211 def renderer view_context || nil # This isn't ideal end |
#report_variables ⇒ Object
201 202 203 |
# File 'app/models/effective/notification.rb', line 201 def report_variables assigns_for().keys end |
#rows_count ⇒ Object
215 216 217 |
# File 'app/models/effective/notification.rb', line 215 def rows_count @rows_count ||= report.collection().count if report end |
#schedule ⇒ Object
151 152 153 154 155 156 157 158 159 |
# File 'app/models/effective/notification.rb', line 151 def schedule if immediate? "Send immediately then every #{immediate_days} days for #{immediate_times} times total" elsif scheduled? && scheduled_method == 'dates' "Send on #{scheduled_dates.length} scheduled days: #{scheduled_dates.sort.to_sentence}" else 'todo' end end |
#scheduled? ⇒ Boolean
167 168 169 |
# File 'app/models/effective/notification.rb', line 167 def scheduled? schedule_type == 'scheduled' end |
#scheduled_dates ⇒ Object
189 190 191 |
# File 'app/models/effective/notification.rb', line 189 def scheduled_dates Array(self[:scheduled_dates]) - [nil, ''] end |
#scheduled_email? ⇒ Boolean
Only scheduled emails can have attached reports. Only scheduled emails can do Send Now
181 182 183 |
# File 'app/models/effective/notification.rb', line 181 def scheduled_email? scheduled? && audience_emails? end |
#send_now! ⇒ Object
Enqueues this notification to send right away. Only applies to scheduled_email? notifications
237 238 239 240 241 |
# File 'app/models/effective/notification.rb', line 237 def send_now! raise('expected to be persisted') unless persisted? NotificationJob.perform_later(id, force: true) true end |
#skip_once! ⇒ Object
Only applies to immedate? notifications Skips over one notification on the immediate notifications
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'app/models/effective/notification.rb', line 245 def skip_once! notified = 0 report.collection().find_each do |resource| print('.') # For logging assign_attributes(current_resource: resource) # Send the resource email build_notification_log(resource: resource, skipped: true).save! notified += 1 GC.start if (notified % 250) == 0 end touch end |
#template_body ⇒ Object
197 198 199 |
# File 'app/models/effective/notification.rb', line 197 def template_body Liquid::Template.parse(body) end |
#template_subject ⇒ Object
193 194 195 |
# File 'app/models/effective/notification.rb', line 193 def template_subject Liquid::Template.parse(subject) end |
#to_s ⇒ Object
147 148 149 |
# File 'app/models/effective/notification.rb', line 147 def to_s subject.presence || model_name.human end |