Module: SimpleNotifications::Base

Defined in:
lib/simple_notifications/base.rb,
lib/simple_notifications/notification_actions.rb

Defined Under Namespace

Modules: NotificationActions

Instance Method Summary collapse

Instance Method Details

#acts_as_notifier(options = {}) ⇒ Object

notify sender: :product_class,

receivers: :variants,
action: [:follow, :update, :create, :destroy]


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/simple_notifications/base.rb', line 8

def acts_as_notifier(options = {})
  Base.options = options
  raise 'SimpleNotifications::ActionsNotAvailable' if Base.options[:actions].nil? || Base.options[:actions].empty?

  # Default Assumptions
  Base.options[:sender] ||= :user # Default Assumption: [:user] association is available.
  Base.options[:entity_class] = self

  # Filter system defined callback actions
  # After this
  # Base.options[:callbacks] -> will have all system defined actions only like (create/update/destroy)
  # Base.options[:actions]   -> will have user defined actions only.
  Base.options[:callbacks] = []
  %i[create update destroy].each {|method| Base.options[:callbacks] << Base.options[:actions].delete(method)}
  Base.options[:callbacks].compact!

  open_sender_class
  open_receiver_class
  open_notified_class

  Base.active = true
end

#notifications_active?Boolean

Getter to check if model is enabled with notifications

Returns:

  • (Boolean)


32
33
34
# File 'lib/simple_notifications/base.rb', line 32

def notifications_active?
  !!Base.active
end

#open_notified_classObject

Opening the class on which the notify functionality is applied.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/simple_notifications/base.rb', line 56

def open_notified_class
  class_eval do
    prepend NotificationActions # For adding all user defined methods at the last level of present class
    attr_accessor :message, :notify_flag

    # -------------------------------------------------- #
    # Define association for the notified model
    # -------------------------------------------------- #
    has_many :notifications, class_name: 'SimpleNotifications::Record', as: :entity
    has_many :notifiers, through: :notifications, source: :sender,
             source_type: sender_class(Base.options[:sender]).to_s
    has_many :read_deliveries, through: :notifications, source: :read_deliveries
    has_many :unread_deliveries, through: :notifications, source: :unread_deliveries

    # -------------------------------------------------- #
    # For defining the System defined callbacks
    # -------------------------------------------------- #

    # Callbacks
    # after_create_commit :create_notification
    Base.options[:callbacks].each do |callback|
      send("after_#{callback}_commit", "#{callback}_notification".to_sym)
    end

    def create_notification
      notify(sender: get_obj(Base.options[:sender]),
             receivers: get_obj(Base.options[:receivers]),
             action: 'create',
             message: default_message(self, get_obj(Base.options[:sender]), 'created'))
    end

    def update_notification
      notify(sender: get_obj(Base.options[:sender]),
             receivers: get_obj(Base.options[:receivers]),
             action: 'update',
             message: default_message(self, get_obj(Base.options[:sender]), 'updated'))
    end

    def destroy_notification
      notify(sender: get_obj(Base.options[:sender]),
             receivers: get_obj(Base.options[:receivers]),
             action: 'destroy',
             message: default_message(self, get_obj(Base.options[:sender]), 'destroyed'))
    end

    # -------------------------------------------------- #
    # For defining the callbacks for user defined actions
    # -------------------------------------------------- #
    NotificationActions.module_eval do
      Base.options[:actions].each do |action|
        define_method(action) do
          run_callbacks action do
            super()
          end
        end

        define_method("before_#{action}".to_sym) do
        end

        define_method("after_#{action}".to_sym) do
          notify(sender: Base.options[:sender],
                 receivers: Base.options[:receivers],
                 action: action,
                 message: default_message(self, Base.options[:sender], action.to_s))
        end
      end
    end

    Base.options[:actions].each do |action|
      define_model_callbacks action
      send("before_#{action}", "before_#{action}".to_sym)
      send("after_#{action}", "after_#{action}".to_sym)
    end

    # -------------------------------------------------- #
    # Example
    # post.notify(sender: :author, receivers: :followers, message: 'My Custom logic message')
    # post.create(content: '', notify: false) -> It does not create the notification.
    def notify(options = {})
      options[:sender] ||= Base.options[:sender]
      options[:receivers] ||= Base.options[:receivers]
      if notify_flag.nil? || (!notify_flag.nil? && !!notify_flag)
        raise 'SimpleNotification::SenderReceiverError' unless Base.options[:sender] && Base.options[:receivers]

        @message = options[:message] if options[:message]
        notification = notifications.build(entity: self,
                                           sender: get_obj(options[:sender]),
                                           action: options[:action] || '',
                                           message: default_message(self, get_obj(options[:sender]), 'notified'))
        [get_obj(options[:receivers])].flatten.each {|receiver| notification.deliveries.build(receiver: receiver)}
        notification.save
      end
    end

    def flush_notifications
      notifications.destroy_all
    end

    # Check if notifications has already been delivered.
    def notified?
      !notifications.blank?
    end

    def notificants
      SimpleNotifications::Record.includes(deliveries: :receiver)
        .collect(&:deliveries).flatten
        .collect(&:receiver)
    end

    def read_marked_notificants
      SimpleNotifications::Record.includes(deliveries: :receiver)
        .collect(&:deliveries).flatten
        .select(&:is_read)
        .collect(&:receiver)
    end

    def unread_marked_notificants
      SimpleNotifications::Record
        .includes(deliveries: :receiver)
        .collect(&:deliveries).flatten
        .reject {|record| record.is_read}.collect(&:receiver)
    end

    # Mark notifications in read mode.
    # If notificants are provided then only those respective notifications will be marked read.
    # Else all will be marked as read.
    def mark_read(notificants = nil)
      (notificants ? unread_deliveries.where(receiver: notificants) : unread_deliveries).update_all(is_read: true)
    end

    # Mark notifications in unread mode.
    # If notificants are provided then only those respective notifications will be marked unread.
    # Else all will be marked as unread.
    def mark_unread(notificants = nil)
      (notificants ? read_deliveries.where(receiver: notificants) : read_deliveries).update_all(is_read: false)
    end

    def default_message(entity, sender, action)
      @message ||
        (method(Base.options[:notify_message]).call if !!Base.options[:notify_message]) ||
        "#{get_obj(sender).class.name} #{action} #{entity.class.name} #{entity.name}"
    end

    private

    def get_obj(sender_or_receivers)
      sender_or_receivers.kind_of?(Symbol) ? send(sender_or_receivers) : sender_or_receivers
    end
  end
end

#open_receiver_classObject

Opening the classes which are defined as receivers.



45
46
47
48
49
50
51
52
53
# File 'lib/simple_notifications/base.rb', line 45

def open_receiver_class
  # Define association for receiver model
  [receivers_class(Base.options[:receivers])].flatten.each do |base|
    base.class_eval do
      has_many :deliveries, class_name: 'SimpleNotifications::Delivery', as: :receiver
      has_many :received_notifications, through: :deliveries, source: :simple_notification
    end
  end
end

#open_sender_classObject

Opening the class which is defined as sender.



37
38
39
40
41
42
# File 'lib/simple_notifications/base.rb', line 37

def open_sender_class
  # Define association for sender model
  sender_class(Base.options[:sender]).class_eval do
    has_many :sent_notifications, class_name: 'SimpleNotifications::Record', as: :sender
  end
end

#receivers_class(receivers) ⇒ Object

Provides the classes of Receivers



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/simple_notifications/base.rb', line 219

def receivers_class(receivers)
  if receivers.kind_of? Symbol
    reflections[receivers.to_s].klass
  else
    if receivers.kind_of? ActiveRecord::Base
      receivers.class
    elsif receivers.kind_of? ActiveRecord::Relation
      receivers.klass
    elsif receivers.kind_of? Array
      receivers.flatten.collect {|receiver| receivers_class(receiver)}
    else
      raise 'SimpleNotifications::ReceiverTypeError'
    end
  end
end

#sender_class(sender) ⇒ Object

Provides the class of Sender



208
209
210
211
212
213
214
215
216
# File 'lib/simple_notifications/base.rb', line 208

def sender_class(sender)
  if sender.kind_of? Symbol
    reflections[sender.to_s].klass
  elsif sender.kind_of? ActiveRecord::Base
    sender.class
  else
    raise 'SimpleNotifications::SenderTypeError'
  end
end