Class: NotifyUser::BaseNotification
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- NotifyUser::BaseNotification
- Includes:
- AASM, ActionView::Helpers::TextHelper
- Defined in:
- app/models/notify_user/base_notification.rb
Class Method Summary collapse
- .aggregate_message(notifications) ⇒ Object
-
.channel(name, options = {}) ⇒ Object
Configure a channel.
-
.deliver_channels(notification_id) ⇒ Object
Deliver a single notification across each channel.
-
.deliver_channels_aggregated(notifications) ⇒ Object
Deliver multiple notifications across each channel as an aggregate message.
-
.deliver_notification_channel(notification_id, channel_name) ⇒ Object
Deliver a single notification to a specific channel.
-
.deliver_notifications_channel(notifications, channel_name) ⇒ Object
Deliver a aggregated notifications to a specific channel.
-
.for_target(target) ⇒ Object
Sending.
-
.notify_aggregated_channel(notification_id, channel_name) ⇒ Object
Prepares a single channel for aggregation.
-
.pending_aggregation_by_group_with(notification) ⇒ Object
Used to find all pending notifications with aggregation enabled for target.
-
.pending_aggregation_with(notification) ⇒ Object
Used to find all pending notifications for target.
-
.pending_aggregations_grouped_marked_as_parent(notification) ⇒ Object
Used for aggregation when grouping based on group_id for target.
-
.pending_aggregations_marked_as_parent(notification) ⇒ Object
Used for aggregation when grouping isn’t enabled.
Instance Method Summary collapse
-
#aggregate_grouping ⇒ Object
True will implement a grouping/aggregation algorithm so that even though 10 notifications are delivered eg.
-
#aggregate_per ⇒ Object
Aggregation.
- #aggregation_interval ⇒ Object
- #aggregation_parents ⇒ Object
- #aggregation_pending? ⇒ Boolean
-
#channels ⇒ Object
Channels.
-
#count_for_target ⇒ Object
returns the global unread notification count for a user.
-
#current_parents ⇒ Object
Returns all parent notifications with a given group_id.
- #delay_time(options) ⇒ Object
-
#deliver ⇒ Object
Aggregates appropriately.
-
#deliver! ⇒ Object
Sends immediately and without aggregation.
-
#description ⇒ Object
Notification description.
- #generate_unsubscribe_hash ⇒ Object
- #grouped_by_id(group_id) ⇒ Object
- #message ⇒ Object
- #mobile_message(length = 115) ⇒ Object
-
#notify(deliver = true) ⇒ Object
Send any Emails/SMS/APNS.
- #notify! ⇒ Object
- #params ⇒ Object
- #pending_and_sent_aggregation_parents ⇒ Object
- #sent_aggregation_parents ⇒ Object
-
#to(user) ⇒ Object
Public Interface.
- #user_has_unsubscribed?(channel_name = nil) ⇒ Boolean
- #with(*args) ⇒ Object
Class Method Details
.aggregate_message(notifications) ⇒ Object
94 95 96 97 98 99 100 101 |
# File 'app/models/notify_user/base_notification.rb', line 94 def self.(notifications) string = ActionView::Base.new( ActionController::Base.view_paths).render( :template => self.class.views[:mobile_sdk][:aggregate_path].call(self), :formats => [:html], :locals => { :notifications => notifications}) return ::CGI.unescapeHTML("#{string}") end |
.channel(name, options = {}) ⇒ Object
Configure a channel
215 216 217 218 219 |
# File 'app/models/notify_user/base_notification.rb', line 215 def self.channel(name, ={}) channels_clone = self.channels.clone channels_clone[name] = self.channels = channels_clone end |
.deliver_channels(notification_id) ⇒ Object
Deliver a single notification across each channel.
328 329 330 331 332 |
# File 'app/models/notify_user/base_notification.rb', line 328 def self.deliver_channels(notification_id) self.channels.each do |channel_name, | self.deliver_notification_channel(notification_id, channel_name) end end |
.deliver_channels_aggregated(notifications) ⇒ Object
Deliver multiple notifications across each channel as an aggregate message.
335 336 337 338 339 340 341 342 |
# File 'app/models/notify_user/base_notification.rb', line 335 def self.deliver_channels_aggregated(notifications) self.channels.each do |channel_name, | if [:aggregate_per] != false && !unsubscribed_from_channel?(notifications.first.target, channel_name) channel = (channel_name.to_s + "_channel").camelize.constantize channel.deliver_aggregated(notifications, ) end end end |
.deliver_notification_channel(notification_id, channel_name) ⇒ Object
Deliver a single notification to a specific channel.
347 348 349 350 351 352 353 354 355 356 |
# File 'app/models/notify_user/base_notification.rb', line 347 def self.deliver_notification_channel(notification_id, channel_name) notification = self.find(notification_id) # Raise an exception if not found. = channels[channel_name.to_sym] channel = (channel_name.to_s + "_channel").camelize.constantize unless notification.user_has_unsubscribed?(channel_name) channel.deliver(notification, ) end end |
.deliver_notifications_channel(notifications, channel_name) ⇒ Object
Deliver a aggregated notifications to a specific channel.
359 360 361 362 363 364 365 366 367 |
# File 'app/models/notify_user/base_notification.rb', line 359 def self.deliver_notifications_channel(notifications, channel_name) = channels[channel_name.to_sym] channel = (channel_name.to_s + "_channel").camelize.constantize #check if user unsubsribed from channel type unless notifications.first.user_has_unsubscribed?(channel_name) channel.deliver_aggregated(notifications, ) end end |
.for_target(target) ⇒ Object
Sending
223 224 225 226 |
# File 'app/models/notify_user/base_notification.rb', line 223 def self.for_target(target) where(target_id: target.id) .where(target_type: target.class.base_class) end |
.notify_aggregated_channel(notification_id, channel_name) ⇒ Object
Prepares a single channel for aggregation
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'app/models/notify_user/base_notification.rb', line 370 def self.notify_aggregated_channel(notification_id, channel_name) notification = self.find(notification_id) # Raise an exception if not found. # Find any pending notifications with the same type and target, which can all be sent in one message. if self.aggregate_grouping notifications = self.pending_aggregation_by_group_with(notification) else notifications = self.pending_aggregation_with(notification) end notifications.map(&:mark_as_sent) notifications.map(&:save) # If the notification has been marked as read before it's sent we don't want to send it. return if notification.read? || notifications.empty? if notifications.length == 1 # Despite waiting for more to aggregate, we only got one in the end. self.deliver_notification_channel(notifications.first.id, channel_name) else # We got several notifications while waiting, send them aggregated. self.deliver_notifications_channel(notifications, channel_name) end end |
.pending_aggregation_by_group_with(notification) ⇒ Object
Used to find all pending notifications with aggregation enabled for target
268 269 270 271 272 |
# File 'app/models/notify_user/base_notification.rb', line 268 def self.pending_aggregation_by_group_with(notification) for_target(notification.target) .where(state: [:pending, :pending_as_aggregation_parent]) .where(group_id: notification.group_id) end |
.pending_aggregation_with(notification) ⇒ Object
Used to find all pending notifications for target
275 276 277 278 279 |
# File 'app/models/notify_user/base_notification.rb', line 275 def self.pending_aggregation_with(notification) where(type: notification.type) .for_target(notification.target) .where(state: [:pending, :pending_as_aggregation_parent]) end |
.pending_aggregations_grouped_marked_as_parent(notification) ⇒ Object
Used for aggregation when grouping based on group_id for target
260 261 262 263 264 265 |
# File 'app/models/notify_user/base_notification.rb', line 260 def self.pending_aggregations_grouped_marked_as_parent(notification) where(type: notification.type) .for_target(notification.target) .where(state: :pending_as_aggregation_parent) .where(group_id: notification.group_id) end |
.pending_aggregations_marked_as_parent(notification) ⇒ Object
Used for aggregation when grouping isn’t enabled
253 254 255 256 257 |
# File 'app/models/notify_user/base_notification.rb', line 253 def self.pending_aggregations_marked_as_parent(notification) where(type: notification.type) .for_target(notification.target) .where(state: :pending_as_aggregation_parent) end |
Instance Method Details
#aggregate_grouping ⇒ Object
True will implement a grouping/aggregation algorithm so that even though 10 notifications are delivered eg. Push Notifications Only 1 notification will be displayed to the user within the notification.json payload
201 |
# File 'app/models/notify_user/base_notification.rb', line 201 class_attribute :aggregate_grouping |
#aggregate_per ⇒ Object
Aggregation
196 |
# File 'app/models/notify_user/base_notification.rb', line 196 class_attribute :aggregate_per |
#aggregation_interval ⇒ Object
166 167 168 |
# File 'app/models/notify_user/base_notification.rb', line 166 def aggregation_interval pending_and_sent_aggregation_parents.count end |
#aggregation_parents ⇒ Object
235 236 237 238 |
# File 'app/models/notify_user/base_notification.rb', line 235 def aggregation_parents current_parents .where('id != ?', id) end |
#aggregation_pending? ⇒ Boolean
281 282 283 284 285 286 287 288 289 290 291 |
# File 'app/models/notify_user/base_notification.rb', line 281 def aggregation_pending? # A notification of the same type, that would have an aggregation job associated with it, # already exists. # When group aggregation is enabled we provide a different scope if self.aggregate_grouping return (self.class.pending_aggregations_grouped_marked_as_parent(self).where('id != ?', id).count > 0) else return (self.class.pending_aggregations_marked_as_parent(self).where('id != ?', id).count > 0) end end |
#channels ⇒ Object
Channels
190 |
# File 'app/models/notify_user/base_notification.rb', line 190 class_attribute :channels |
#count_for_target ⇒ Object
returns the global unread notification count for a user
87 88 89 90 91 92 |
# File 'app/models/notify_user/base_notification.rb', line 87 def count_for_target NotifyUser::BaseNotification.for_target(target) .where('parent_id IS NULL') .where('state IN (?)', ["sent_as_aggregation_parent", "sent", "pending"]) .count end |
#current_parents ⇒ Object
Returns all parent notifications with a given group_id
229 230 231 232 233 |
# File 'app/models/notify_user/base_notification.rb', line 229 def current_parents self.class .for_target(self.target) .where(group_id: group_id) end |
#delay_time(options) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'app/models/notify_user/base_notification.rb', line 170 def delay_time() a_interval = [:aggregate_per][aggregation_interval] # uses the last interval by default once we deplete the intervals a_interval = [:aggregate_per].last if a_interval.nil? # last sent notification last_sent_parent = sent_aggregation_parents.first # Uses the time of the last notification sent otherwise will send it now. delay_time = last_sent_parent ? last_sent_parent.sent_time : created_at # If this is the first notification the aggregate interval will return 0. Thus sending the notification now! return delay_time + a_interval.minutes end |
#deliver ⇒ Object
Aggregates appropriately
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'app/models/notify_user/base_notification.rb', line 294 def deliver if pending? and not user_has_unsubscribed? # if aggregation is false bypass aggregation completely self.channels.each do |channel_name, | if([:aggregate_per] == false) self.mark_as_sent! self.class.delay.deliver_notification_channel(self.id, channel_name) else # only notifies channels if no pending aggregate notifications unless aggregation_pending? self.mark_as_pending_as_aggregation_parent! # adds fallback support for integer or array of integers if [:aggregate_per].kind_of?(Array) self.class.delay_until(delay_time()).notify_aggregated_channel(self.id, channel_name) else a_interval = [:aggregate_per] ? [:aggregate_per].minutes : self.aggregate_per self.class.delay_for(a_interval).notify_aggregated_channel(self.id, channel_name) end end end end end end |
#deliver! ⇒ Object
Sends immediately and without aggregation
320 321 322 323 324 325 |
# File 'app/models/notify_user/base_notification.rb', line 320 def deliver! if pending_no_aggregation? and not user_has_unsubscribed? self.mark_as_sent! self.class.deliver_channels(self.id) end end |
#description ⇒ Object
Notification description
186 |
# File 'app/models/notify_user/base_notification.rb', line 186 class_attribute :description |
#generate_unsubscribe_hash ⇒ Object
161 162 163 164 |
# File 'app/models/notify_user/base_notification.rb', line 161 def generate_unsubscribe_hash #check if a hash already exists for that user otherwise create a new one return NotifyUser::UserHash.where(target_id: self.target.id).where(target_type: self.target.class.base_class).where(type: self.type).where(active: true).first || NotifyUser::UserHash.create(target: self.target, type: self.type, active: true) end |
#grouped_by_id(group_id) ⇒ Object
132 133 134 135 |
# File 'app/models/notify_user/base_notification.rb', line 132 def grouped_by_id(group_id) self.group_id = group_id self end |
#message ⇒ Object
103 104 105 106 107 108 109 110 |
# File 'app/models/notify_user/base_notification.rb', line 103 def string = ActionView::Base.new( ActionController::Base.view_paths).render( :template => self.class.views[:mobile_sdk][:template_path].call(self), :formats => [:html], :locals => { :params => self.params, :notification => self}) return ::CGI.unescapeHTML("#{string}") end |
#mobile_message(length = 115) ⇒ Object
112 113 114 115 116 117 118 119 |
# File 'app/models/notify_user/base_notification.rb', line 112 def (length=115) string = truncate(ActionView::Base.new( ActionController::Base.view_paths).render( :template => self.class.views[:mobile_sdk][:template_path].call(self), :formats => [:html], :locals => { :params => self.params, :notification => self}), :length => length) return ::CGI.unescapeHTML("#{string}") end |
#notify(deliver = true) ⇒ Object
Send any Emails/SMS/APNS
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'app/models/notify_user/base_notification.rb', line 143 def notify(deliver=true) #All notifications except the notification at interval 0 should have there parent_id set if self.aggregate_grouping parents = current_parents.where(parent_id: nil).where('created_at >= ?', 24.hours.ago).order('created_at DESC') if parents.any? self.parent_id = parents.first.id end end # Sends with aggregation if enabled save ## if deliver == false don't perform deliver log but still perform aggregation logic ## notification then gets marked as sent mark_as_sent! unless deliver end |
#notify! ⇒ Object
137 138 139 140 |
# File 'app/models/notify_user/base_notification.rb', line 137 def notify! # Bang version of 'notify' ignores aggregation dont_aggregate! end |
#params ⇒ Object
78 79 80 81 82 83 84 |
# File 'app/models/notify_user/base_notification.rb', line 78 def params if super.nil? {} else super.with_indifferent_access end end |
#pending_and_sent_aggregation_parents ⇒ Object
246 247 248 249 250 |
# File 'app/models/notify_user/base_notification.rb', line 246 def pending_and_sent_aggregation_parents aggregation_parents .where(state: [:sent_as_aggregation_parent, :pending_as_aggregation_parent]) .order('created_at DESC') end |
#sent_aggregation_parents ⇒ Object
240 241 242 243 244 |
# File 'app/models/notify_user/base_notification.rb', line 240 def sent_aggregation_parents aggregation_parents .where(state: :sent_as_aggregation_parent) .order('created_at DESC') end |
#to(user) ⇒ Object
Public Interface
122 123 124 125 |
# File 'app/models/notify_user/base_notification.rb', line 122 def to(user) self.target = user self end |
#user_has_unsubscribed?(channel_name = nil) ⇒ Boolean
395 396 397 398 |
# File 'app/models/notify_user/base_notification.rb', line 395 def user_has_unsubscribed?(channel_name=nil) #return true if user has unsubscribed return Unsubscribe.has_unsubscribed_from?(self.target, self.type, self.group_id, channel_name) end |
#with(*args) ⇒ Object
127 128 129 130 |
# File 'app/models/notify_user/base_notification.rb', line 127 def with(*args) self.params = args.reduce({}, :update) self end |