module ActivityNotification::NotificationApi
Defines API for notification included in Notification
model.
Public Class Methods
Returns earliest notification instance. @return [Notification] Earliest notification instance
# File lib/activity_notification/apis/notification_api.rb, line 167 def self.earliest earliest_order.first end
Returns earliest notification instance. This method is to be overridden in implementation for each ORM
. @return [Notification] Earliest notification instance
# File lib/activity_notification/apis/notification_api.rb, line 181 def self.earliest! earliest end
Returns latest notification instance. @return [Notification] Latest notification instance
# File lib/activity_notification/apis/notification_api.rb, line 161 def self.latest latest_order.first end
Returns latest notification instance. This method is to be overridden in implementation for each ORM
. @return [Notification] Latest notification instance
# File lib/activity_notification/apis/notification_api.rb, line 174 def self.latest! latest end
Selects unique keys from query for notifications. @return [Array<String>] Array of notification unique keys
# File lib/activity_notification/apis/notification_api.rb, line 187 def self.uniq_keys ## select method cannot be chained with order by other columns like created_at # select(:key).distinct.pluck(:key) ## distinct method cannot keep original sort # distinct(:key) pluck(:key).uniq end
Public Instance Methods
Call after store action with stored notification
# File lib/activity_notification/apis/notification_api.rb, line 511 def after_store end
Returns available options for kinds of notify methods.
@return [Array<Notificaion>] Available options for kinds of notify methods
# File lib/activity_notification/apis/notification_api.rb, line 456 def available_options [:key, :group, :group_expiry_delay, :notifier, :parameters, :send_email, :send_later, :pass_full_options].freeze end
Returns if the target subscribes this notification email. @return [Boolean] If the target subscribes the notification
# File lib/activity_notification/apis/notification_api.rb, line 700 def email_subscribed? target.subscribes_to_notification_email?(key) end
Generates a notification @param [Object] target Target
to send notification @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notification @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications
# File lib/activity_notification/apis/notification_api.rb, line 394 def generate_notification(target, notifiable, options = {}) key = options[:key] || notifiable.default_notification_key if target.subscribes_to_notification?(key) # Store notification notification = store_notification(target, notifiable, key, options) end end
Returns if the notification is group member belonging to owner.
@return [Boolean] If the notification is group member
# File lib/activity_notification/apis/notification_api.rb, line 593 def group_member? group_owner_id.present? end
Returns count of group members of the notification. This method is designed to cache group by query result to avoid N+1 call.
@param [Integer] limit Limit to query for opened notifications @return [Integer] Count of group members of the notification
# File lib/activity_notification/apis/notification_api.rb, line 622 def group_member_count(limit = ActivityNotification.config.opened_index_limit) meta_group_member_count(:opened_group_member_count, :unopened_group_member_count, limit) end
Returns if group member of the notifications exists. This method is designed to be called from controllers or views to avoid N+1.
@param [Array<Notificaion>, ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] notifications Array or database query of the notifications to test member exists @return [Boolean] If group member of the notifications exists
# File lib/activity_notification/apis/notification_api.rb, line 428 def group_member_exists?(notifications) notifications.present? and group_members_of_owner_ids_only(notifications.map(&:id)).exists? end
Returns count of group member notifiers of the notification not including group owner notifier. It always returns 0 if group owner notifier is blank. It counts only the member notifier of the same type with group owner notifier. This method is designed to cache group by query result to avoid N+1 call.
@param [Integer] limit Limit to query for opened notifications @return [Integer] Count of group member notifiers of the notification
# File lib/activity_notification/apis/notification_api.rb, line 642 def group_member_notifier_count(limit = ActivityNotification.config.opened_index_limit) meta_group_member_count(:opened_group_member_notifier_count, :unopened_group_member_notifier_count, limit) end
Returns if group member notifier except group owner notifier exists. It always returns false if group owner notifier is blank. It counts only the member notifier of the same type with group owner notifier. This method is designed to cache group by query result to avoid N+1 call.
@param [Integer] limit Limit to query for opened notifications @return [Boolean] If group member of the notification exists
# File lib/activity_notification/apis/notification_api.rb, line 613 def group_member_notifier_exists?(limit = ActivityNotification.config.opened_index_limit) group_member_notifier_count(limit) > 0 end
Returns count of group notifications including owner and members. This method is designed to cache group by query result to avoid N+1 call.
@param [Integer] limit Limit to query for opened notifications @return [Integer] Count of group notifications including owner and members
# File lib/activity_notification/apis/notification_api.rb, line 631 def group_notification_count(limit = ActivityNotification.config.opened_index_limit) group_member_count(limit) + 1 end
Returns count of group member notifiers including group owner notifier. It always returns 0 if group owner notifier is blank. This method is designed to cache group by query result to avoid N+1 call.
@param [Integer] limit Limit to query for opened notifications @return [Integer] Count of group notifications including owner and members
# File lib/activity_notification/apis/notification_api.rb, line 652 def group_notifier_count(limit = ActivityNotification.config.opened_index_limit) notification = group_member? && group_owner.present? ? group_owner : self notification.notifier.present? ? group_member_notifier_count(limit) + 1 : 0 end
Returns if the notification is group owner.
@return [Boolean] If the notification is group owner
# File lib/activity_notification/apis/notification_api.rb, line 586 def group_owner? !group_member? end
Returns the latest group member notification instance of this notification. If this group owner has no group members, group owner instance self will be returned.
@return [Notificaion] Notification
instance of the latest group member notification
# File lib/activity_notification/apis/notification_api.rb, line 661 def latest_group_member notification = group_member? && group_owner.present? ? group_owner : self notification.group_member_exists? ? notification.group_members.latest : self end
Returns notifiable_path
to move after opening notification with notifiable.notifiable_path.
@return [String] Notifiable
path URL to move after opening notification
# File lib/activity_notification/apis/notification_api.rb, line 681 def notifiable_path notifiable.blank? and raise ActivityNotification::NotifiableNotFoundError.new("Couldn't find associated notifiable (#{notifiable_type}) of #{self.class.name} with 'id'=#{id}") notifiable.notifiable_path(target_type, key) end
Generates notifications to configured targets with notifiable model.
@example Use with target_type as Symbol
ActivityNotification::Notification.notify :users, @comment
@example Use with target_type as String
ActivityNotification::Notification.notify 'User', @comment
@example Use with target_type as Class
ActivityNotification::Notification.notify User, @comment
@example Use with options
ActivityNotification::Notification.notify :users, @comment, key: 'custom.comment', group: @comment.article ActivityNotification::Notification.notify :users, @comment, parameters: { reply_to: @comment.reply_to }, send_later: false
@param [Symbol, String
, Class] target_type Type of target @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notifications @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously @option options [Boolean] :send_email (true) Whether it sends notification email @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options @return [Array<Notificaion>] Array of generated notifications
# File lib/activity_notification/apis/notification_api.rb, line 226 def notify(target_type, notifiable, options = {}) if options[:notify_later] notify_later(target_type, notifiable, options) else targets = notifiable.notification_targets(target_type, options[:pass_full_options] ? options : options[:key]) unless targets.blank? notify_all(targets, notifiable, options) end end end
Generates notifications to specified targets.
@example Notify to all users
ActivityNotification::Notification.notify_all User.all, @comment
@param [Array<Object>] targets Targets to send notifications @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notifications @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously @option options [Boolean] :send_email (true) Whether it sends notification email @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options @return [Array<Notificaion>] Array of generated notifications
# File lib/activity_notification/apis/notification_api.rb, line 289 def notify_all(targets, notifiable, options = {}) if options[:notify_later] notify_all_later(targets, notifiable, options) else targets.map { |target| notify_to(target, notifiable, options) } end end
Generates notifications to specified targets later by ActiveJob queue.
@example Notify to all users later
ActivityNotification::Notification.notify_all_later User.all, @comment
@param [Array<Object>] targets Targets to send notifications @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notifications @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications @option options [Boolean] :send_email (true) Whether it sends notification email @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options @return [Array<Notificaion>] Array of generated notifications
# File lib/activity_notification/apis/notification_api.rb, line 316 def notify_all_later(targets, notifiable, options = {}) options.delete(:notify_later) ActivityNotification::NotifyAllJob.perform_later(targets, notifiable, options) end
Generates notifications to configured targets with notifiable model later by ActiveJob queue.
@example Use with target_type as Symbol
ActivityNotification::Notification.notify_later :users, @comment
@example Use with target_type as String
ActivityNotification::Notification.notify_later 'User', @comment
@example Use with target_type as Class
ActivityNotification::Notification.notify_later User, @comment
@example Use with options
ActivityNotification::Notification.notify_later :users, @comment, key: 'custom.comment', group: @comment.article ActivityNotification::Notification.notify_later :users, @comment, parameters: { reply_to: @comment.reply_to }, send_later: false
@param [Symbol, String
, Class] target_type Type of target @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notifications @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications @option options [Boolean] :send_email (true) Whether it sends notification email @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options @return [Array<Notificaion>] Array of generated notifications
# File lib/activity_notification/apis/notification_api.rb, line 264 def notify_later(target_type, notifiable, options = {}) target_type = target_type.to_s if target_type.is_a? Symbol options.delete(:notify_later) ActivityNotification::NotifyJob.perform_later(target_type, notifiable, options) end
Generates notifications to one target later by ActiveJob queue.
@example Notify to one user later
ActivityNotification::Notification.notify_later_to @comment.auther, @comment
@param [Object] target Target
to send notifications @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notifications @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications @option options [Boolean] :send_email (true) Whether it sends notification email @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options @return [Notification] Generated notification instance
# File lib/activity_notification/apis/notification_api.rb, line 381 def notify_later_to(target, notifiable, options = {}) options.delete(:notify_later) ActivityNotification::NotifyToJob.perform_later(target, notifiable, options) end
Generates notifications to one target.
@example Notify to one user
ActivityNotification::Notification.notify_to @comment.auther, @comment
@param [Object] target Target
to send notifications @param [Object] notifiable Notifiable
instance @param [Hash] options Options for notifications @option options [String] :key (notifiable.default_notification_key) Key of the notification @option options [Object] :group (nil) Group
unit of the notifications @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group @option options [Object] :notifier (nil) Notifier
of the notifications @option options [Hash] :parameters ({}) Additional parameters of the notifications @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously @option options [Boolean] :send_email (true) Whether it sends notification email @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options @return [Notification] Generated notification instance
# File lib/activity_notification/apis/notification_api.rb, line 340 def notify_to(target, notifiable, options = {}) if options[:notify_later] notify_later_to(target, notifiable, options) else send_email = options.has_key?(:send_email) ? options[:send_email] : true send_later = options.has_key?(:send_later) ? options[:send_later] : true publish_optional_targets = options.has_key?(:publish_optional_targets) ? options[:publish_optional_targets] : true # Generate notification notification = generate_notification(target, notifiable, options) # Send notification email if notification.present? && send_email notification.send_notification_email({ send_later: send_later }) end # Publish to optional targets if notification.present? && publish_optional_targets notification.publish_to_optional_targets(options[:optional_targets] || {}) end # Return generated notification notification end end
Opens the notification.
@param [Hash] options Options for opening notifications @option options [DateTime] :opened_at (Time.current) Time to set to opened_at of the notification record @option options [Boolean] :with_members (true) If it opens notifications including group members @return [Integer] Number of opened notification records
# File lib/activity_notification/apis/notification_api.rb, line 559 def open!(options = {}) opened? and return 0 opened_at = options[:opened_at] || Time.current with_members = options.has_key?(:with_members) ? options[:with_members] : true unopened_member_count = with_members ? group_members.unopened_only.count : 0 group_members.update_all(opened_at: opened_at) if with_members update(opened_at: opened_at) unopened_member_count + 1 end
Opens all notifications of the target.
@param [Object] target Target
of the notifications to open @param [Hash] options Options for opening notifications @option options [DateTime] :opened_at (Time.current) Time to set to opened_at of the notification record @option options [String] :filtered_by_type (nil) Notifiable
type for filter @option options [Object] :filtered_by_group (nil) Group
instance for filter @option options [String] :filtered_by_group_type (nil) Group
type for filter, valid with :filtered_by_group_id @option options [String] :filtered_by_group_id (nil) Group
instance id for filter, valid with :filtered_by_group_type @option options [String] :filtered_by_key (nil) Key of the notification for filter @option options [String] :later_than (nil) ISO 8601 format time to filter notification index later than specified time @option options [String] :earlier_than (nil) ISO 8601 format time to filter notification index earlier than specified time @return [Array<Notification>] Opened notification records
# File lib/activity_notification/apis/notification_api.rb, line 415 def open_all_of(target, options = {}) opened_at = options[:opened_at] || Time.current target_unopened_notifications = target.notifications.unopened_only.filtered_by_options(options) opened_notifications = target_unopened_notifications.to_a.map { |n| n.opened_at = opened_at; n } target_unopened_notifications.update_all(opened_at: opened_at) opened_notifications end
Returns if the notification is opened.
@return [Boolean] If the notification is opened
# File lib/activity_notification/apis/notification_api.rb, line 579 def opened? opened_at.present? end
Returns optional_target names of the notification from configured field or overridden method. @return [Array<Symbol>] Array of optional target names
# File lib/activity_notification/apis/notification_api.rb, line 719 def optional_target_names notifiable.optional_target_names(target.to_resources_name, key) end
Returns if the target subscribes this notification email. @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack) @return [Boolean] If the target subscribes the specified optional target of the notification
# File lib/activity_notification/apis/notification_api.rb, line 707 def optional_target_subscribed?(optional_target_name) target.subscribes_to_optional_target?(key, optional_target_name) end
Returns optional_targets
of the notification from configured field or overridden method. @return [Array<ActivityNotification::OptionalTarget::Base>] Array of optional target instances
# File lib/activity_notification/apis/notification_api.rb, line 713 def optional_targets notifiable.optional_targets(target.to_resources_name, key) end
:nocov: Returns prepared notification object to store @return [Object] prepared notification object to store
# File lib/activity_notification/apis/notification_api.rb, line 506 def prepare_to_store self end
Returns printable notifiable model name to show in view or email. @return [String] Printable notifiable model name
# File lib/activity_notification/apis/notification_api.rb, line 688 def printable_notifiable_name notifiable.printable_notifiable_name(target, key) end
Publishes notification to the optional targets.
@param [Hash] options Options for optional targets @return [Hash] Result of publishing to optional target
# File lib/activity_notification/apis/notification_api.rb, line 536 def publish_to_optional_targets(options = {}) notifiable.optional_targets(target.to_resources_name, key).map { |optional_target| optional_target_name = optional_target.to_optional_target_name if optional_target_subscribed?(optional_target_name) begin optional_target.notify(self, options[optional_target_name] || {}) [optional_target_name, true] rescue => e Rails.logger.error(e) [optional_target_name, e] end else [optional_target_name, false] end }.to_h end
Remove from notification group and make a new group owner.
@return [Notificaion] New group owner instance of the notification group
# File lib/activity_notification/apis/notification_api.rb, line 669 def remove_from_group new_group_owner = group_members.earliest if new_group_owner.present? new_group_owner.update(group_owner_id: nil) group_members.update_all(group_owner_id: new_group_owner.id) end new_group_owner end
Sends batch notification email to the target.
@param [Object] target Target
of batch notification email @param [Array<Notification>] notifications Target
notifications to send batch notification email @param [Hash] options Options for notification email @option options [Boolean] :send_later (false) If it sends notification email asynchronously @option options [String, Symbol] :fallback (:batch_default) Fallback template to use when MissingTemplate is raised @option options [String] :batch_key (nil) Key of the batch notification email, a key of the first notification will be used if not specified @return [Mail::Message, ActionMailer::DeliveryJob|NilClass] Email message or its delivery job, return NilClass for wrong target
# File lib/activity_notification/apis/notification_api.rb, line 441 def send_batch_notification_email(target, notifications, options = {}) notifications.blank? and return batch_key = options[:batch_key] || notifications.first.key if target.batch_notification_email_allowed?(batch_key) && target.subscribes_to_notification_email?(batch_key) send_later = options.has_key?(:send_later) ? options[:send_later] : true send_later ? @@notification_mailer.send_batch_notification_email(target, notifications, batch_key, options).deliver_later : @@notification_mailer.send_batch_notification_email(target, notifications, batch_key, options).deliver_now end end
Sends notification email to the target.
@param [Hash] options Options for notification email @option options [Boolean] :send_later If it sends notification email asynchronously @option options [String, Symbol] :fallback (:default) Fallback template to use when MissingTemplate is raised @return [Mail::Message, ActionMailer::DeliveryJob] Email message or its delivery job
# File lib/activity_notification/apis/notification_api.rb, line 521 def send_notification_email(options = {}) if target.notification_email_allowed?(notifiable, key) && notifiable.notification_email_allowed?(target, key) && email_subscribed? send_later = options.has_key?(:send_later) ? options[:send_later] : true send_later ? @@notification_mailer.send_notification_email(self, options).deliver_later : @@notification_mailer.send_notification_email(self, options).deliver_now end end
Defines mailer class to send notification
# File lib/activity_notification/apis/notification_api.rb, line 461 def set_notification_mailer @@notification_mailer = ActivityNotification.config.mailer.constantize end
Stores notifications to datastore @api private
# File lib/activity_notification/apis/notification_api.rb, line 486 def store_notification(target, notifiable, key, options = {}) target_type = target.to_class_name group = options[:group] || notifiable.notification_group(target_type, key) group_expiry_delay = options[:group_expiry_delay] || notifiable.notification_group_expiry_delay(target_type, key) notifier = options[:notifier] || notifiable.notifier(target_type, key) parameters = options[:parameters] || {} parameters.merge!(options.except(*available_options)) parameters.merge!(notifiable.notification_parameters(target_type, key)) group_owner = valid_group_owner(target, notifiable, key, group, group_expiry_delay) notification = new({ target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier, group_owner: group_owner }) notification.prepare_to_store.save notification.after_store notification end
Returns if the target subscribes this notification. @return [Boolean] If the target subscribes the notification
# File lib/activity_notification/apis/notification_api.rb, line 694 def subscribed? target.subscribes_to_notification?(key) end
Returns if the notification is unopened.
@return [Boolean] If the notification is unopened
# File lib/activity_notification/apis/notification_api.rb, line 572 def unopened? !opened? end
Returns valid group owner within the expiration period
@param [Object] target Target
to send notifications @param [Object] notifiable Notifiable
instance @param [String] key Key of the notification @param [Object] group Group
unit of the notifications @param [ActiveSupport::Duration] group_expiry_delay Expiry period of a notification group @return [Notificaion] Valid group owner within the expiration period
# File lib/activity_notification/apis/notification_api.rb, line 473 def valid_group_owner(target, notifiable, key, group, group_expiry_delay) return nil if group.blank? # Bundle notification group by target, notifiable_type, group and key # Different notifiable.id can be made in a same group group_owner_notifications = filtered_by_target(target).filtered_by_type(notifiable.to_class_name).filtered_by_key(key) .filtered_by_group(group).group_owners_only.unopened_only group_expiry_delay.present? ? group_owner_notifications.within_expiration_only(group_expiry_delay).earliest : group_owner_notifications.earliest end
Protected Instance Methods
Returns count of various members of the notification. This method is designed to cache group by query result to avoid N+1 call. @api protected
@param [Symbol] opened_member_count_method_name Method name to count members of unopened index @param [Symbol] unopened_member_count_method_name Method name to count members of opened index @param [Integer] limit Limit to query for opened notifications @return [Integer] Count of various members of the notification
# File lib/activity_notification/apis/notification_api.rb, line 733 def meta_group_member_count(opened_member_count_method_name, unopened_member_count_method_name, limit) notification = group_member? && group_owner.present? ? group_owner : self notification.opened? ? notification.send(opened_member_count_method_name, limit) : notification.send(unopened_member_count_method_name) end