activity_notification 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +23 -11
  5. data/Gemfile.lock +52 -40
  6. data/README.md +177 -14
  7. data/activity_notification.gemspec +3 -1
  8. data/app/controllers/activity_notification/subscriptions_controller.rb +48 -2
  9. data/app/views/activity_notification/optional_targets/default/base/_default.text.erb +10 -0
  10. data/app/views/activity_notification/optional_targets/default/slack/_default.text.erb +6 -0
  11. data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +19 -0
  12. data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +32 -3
  13. data/app/views/activity_notification/subscriptions/default/index.html.erb +4 -0
  14. data/app/views/activity_notification/subscriptions/default/show.html.erb +5 -0
  15. data/app/views/activity_notification/subscriptions/default/subscribe_to_optional_target.js.erb +6 -0
  16. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_optional_target.js.erb +6 -0
  17. data/gemfiles/Gemfile.rails-4.2.lock +15 -3
  18. data/gemfiles/Gemfile.rails-5.0.lock +47 -35
  19. data/lib/activity_notification.rb +1 -0
  20. data/lib/activity_notification/apis/notification_api.rb +83 -26
  21. data/lib/activity_notification/apis/subscription_api.rb +93 -8
  22. data/lib/activity_notification/common.rb +6 -2
  23. data/lib/activity_notification/helpers/view_helpers.rb +43 -0
  24. data/lib/activity_notification/models/concerns/notifiable.rb +73 -28
  25. data/lib/activity_notification/models/concerns/subscriber.rb +34 -7
  26. data/lib/activity_notification/models/concerns/target.rb +25 -13
  27. data/lib/activity_notification/models/subscription.rb +13 -2
  28. data/lib/activity_notification/optional_targets/amazon_sns.rb +42 -0
  29. data/lib/activity_notification/optional_targets/base.rb +79 -0
  30. data/lib/activity_notification/optional_targets/slack.rb +33 -0
  31. data/lib/activity_notification/rails/routes.rb +30 -20
  32. data/lib/activity_notification/roles/acts_as_notifiable.rb +70 -11
  33. data/lib/activity_notification/version.rb +1 -1
  34. data/lib/generators/activity_notification/views_generator.rb +2 -2
  35. data/lib/generators/templates/migrations/migration.rb +2 -2
  36. data/spec/concerns/apis/notification_api_spec.rb +97 -0
  37. data/spec/concerns/apis/subscription_api_spec.rb +206 -41
  38. data/spec/concerns/common_spec.rb +7 -2
  39. data/spec/concerns/models/notifiable_spec.rb +88 -2
  40. data/spec/concerns/models/subscriber_spec.rb +114 -13
  41. data/spec/concerns/models/target_spec.rb +17 -0
  42. data/spec/controllers/subscriptions_controller_shared_examples.rb +251 -28
  43. data/spec/helpers/view_helpers_spec.rb +56 -0
  44. data/spec/optional_targets/amazon_sns_spec.rb +46 -0
  45. data/spec/optional_targets/base_spec.rb +43 -0
  46. data/spec/optional_targets/slack_spec.rb +46 -0
  47. data/spec/rails_app/app/controllers/comments_controller.rb +1 -0
  48. data/spec/rails_app/app/models/admin.rb +1 -2
  49. data/spec/rails_app/app/models/article.rb +2 -3
  50. data/spec/rails_app/app/models/comment.rb +19 -7
  51. data/spec/rails_app/app/views/activity_notification/optional_targets/admins/amazon_sns/comment/_default.text.erb +8 -0
  52. data/spec/rails_app/db/migrate/20160715050420_create_activity_notification_tables.rb +1 -1
  53. data/spec/rails_app/db/migrate/20160715050433_create_test_tables.rb +2 -0
  54. data/spec/rails_app/db/schema.rb +3 -1
  55. data/spec/rails_app/db/seeds.rb +1 -1
  56. data/spec/rails_app/lib/custom_optional_targets/console_output.rb +13 -0
  57. data/spec/rails_app/lib/custom_optional_targets/wrong_target.rb +10 -0
  58. data/spec/roles/acts_as_notifiable_spec.rb +124 -2
  59. metadata +49 -4
  60. data/spec/rails_app/app/models/notification.rb +0 -6
@@ -54,6 +54,7 @@ require 'activity_notification/helpers/view_helpers'
54
54
  require 'activity_notification/controllers/common_controller'
55
55
  require 'activity_notification/controllers/store_controller'
56
56
  require 'activity_notification/controllers/devise_authentication_controller'
57
+ require 'activity_notification/optional_targets/base'
57
58
 
58
59
  # Load role for models
59
60
  require 'activity_notification/models'
@@ -24,13 +24,15 @@ module ActivityNotification
24
24
  # @param [Symbol, String, Class] target_type Type of target
25
25
  # @param [Object] notifiable Notifiable instance
26
26
  # @param [Hash] options Options for notifications
27
- # @option options [String] :key (notifiable.default_notification_key) Key of the notification
28
- # @option options [Object] :group (nil) Group unit of the notifications
29
- # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
30
- # @option options [Object] :notifier (nil) Notifier of the notifications
31
- # @option options [Hash] :parameters ({}) Additional parameters of the notifications
32
- # @option options [Boolean] :send_email (true) Whether it sends notification email
33
- # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
27
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
28
+ # @option options [Object] :group (nil) Group unit of the notifications
29
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
30
+ # @option options [Object] :notifier (nil) Notifier of the notifications
31
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
32
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
33
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
34
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
35
+ # @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
34
36
  # @return [Array<Notificaion>] Array of generated notifications
35
37
  def notify(target_type, notifiable, options = {})
36
38
  targets = notifiable.notification_targets(target_type, options[:key])
@@ -47,13 +49,15 @@ module ActivityNotification
47
49
  # @param [Array<Object>] targets Targets to send notifications
48
50
  # @param [Object] notifiable Notifiable instance
49
51
  # @param [Hash] options Options for notifications
50
- # @option options [String] :key (notifiable.default_notification_key) Key of the notification
51
- # @option options [Object] :group (nil) Group unit of the notifications
52
- # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
53
- # @option options [Object] :notifier (nil) Notifier of the notifications
54
- # @option options [Hash] :parameters ({}) Additional parameters of the notifications
55
- # @option options [Boolean] :send_email (true) Whether it sends notification email
56
- # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
52
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
53
+ # @option options [Object] :group (nil) Group unit of the notifications
54
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
55
+ # @option options [Object] :notifier (nil) Notifier of the notifications
56
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
57
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
58
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
59
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
60
+ # @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
57
61
  # @return [Array<Notificaion>] Array of generated notifications
58
62
  def notify_all(targets, notifiable, options = {})
59
63
  targets.map { |target| target.notify_to(notifiable, options) }
@@ -67,23 +71,30 @@ module ActivityNotification
67
71
  # @param [Object] target Target to send notifications
68
72
  # @param [Object] notifiable Notifiable instance
69
73
  # @param [Hash] options Options for notifications
70
- # @option options [String] :key (notifiable.default_notification_key) Key of the notification
71
- # @option options [Object] :group (nil) Group unit of the notifications
72
- # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
73
- # @option options [Object] :notifier (nil) Notifier of the notifications
74
- # @option options [Hash] :parameters ({}) Additional parameters of the notifications
75
- # @option options [Boolean] :send_email (true) Whether it sends notification email
76
- # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
74
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
75
+ # @option options [Object] :group (nil) Group unit of the notifications
76
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
77
+ # @option options [Object] :notifier (nil) Notifier of the notifications
78
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
79
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
80
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
81
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
82
+ # @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
77
83
  # @return [Notification] Generated notification instance
78
84
  def notify_to(target, notifiable, options = {})
79
- send_email = options.has_key?(:send_email) ? options[:send_email] : true
80
- send_later = options.has_key?(:send_later) ? options[:send_later] : true
85
+ send_email = options.has_key?(:send_email) ? options[:send_email] : true
86
+ send_later = options.has_key?(:send_later) ? options[:send_later] : true
87
+ publish_optional_targets = options.has_key?(:publish_optional_targets) ? options[:publish_optional_targets] : true
81
88
  # Generate notification
82
89
  notification = generate_notification(target, notifiable, options)
83
90
  # Send notification email
84
91
  if notification.present? && send_email
85
92
  notification.send_notification_email({ send_later: send_later })
86
93
  end
94
+ # Publish to optional targets
95
+ if notification.present? && publish_optional_targets
96
+ notification.publish_to_optional_targets(options[:optional_targets] || {})
97
+ end
87
98
  # Return generated notification
88
99
  notification
89
100
  end
@@ -192,8 +203,8 @@ module ActivityNotification
192
203
  # @return [Mail::Message, ActionMailer::DeliveryJob] Email message or its delivery job
193
204
  def send_notification_email(options = {})
194
205
  if target.notification_email_allowed?(notifiable, key) &&
195
- email_subscribed?(key) &&
196
- notifiable.notification_email_allowed?(target, key)
206
+ notifiable.notification_email_allowed?(target, key) &&
207
+ email_subscribed?
197
208
  send_later = options.has_key?(:send_later) ? options[:send_later] : true
198
209
  send_later ?
199
210
  Mailer.send_notification_email(self, options).deliver_later :
@@ -201,6 +212,22 @@ module ActivityNotification
201
212
  end
202
213
  end
203
214
 
215
+ # Publishes notification to the optional targets.
216
+ #
217
+ # @param [Hash] options Options for optional targets
218
+ # @return [Hash] Result of publishing to optional target
219
+ def publish_to_optional_targets(options = {})
220
+ notifiable.optional_targets(target.to_resources_name, key).map { |optional_target|
221
+ optional_target_name = optional_target.to_optional_target_name
222
+ if optional_target_subscribed?(optional_target_name)
223
+ optional_target.notify(self, options[optional_target_name] || {})
224
+ [optional_target_name, true]
225
+ else
226
+ [optional_target_name, false]
227
+ end
228
+ }.to_h
229
+ end
230
+
204
231
  # Opens the notification.
205
232
  #
206
233
  # @param [Hash] options Options for opening notifications
@@ -311,6 +338,18 @@ module ActivityNotification
311
338
  notification.group_member_exists? ? notification.group_members.latest : self
312
339
  end
313
340
 
341
+ # Remove from notification group and make a new group owner.
342
+ #
343
+ # @return [Notificaion] New group owner instance of the notification group
344
+ def remove_from_group
345
+ new_group_owner = group_members.earliest
346
+ if new_group_owner.present?
347
+ new_group_owner.update(group_owner_id: nil)
348
+ group_members.update_all(group_owner_id: new_group_owner)
349
+ end
350
+ new_group_owner
351
+ end
352
+
314
353
  # Returns notifiable_path to move after opening notification with notifiable.notifiable_path.
315
354
  #
316
355
  # @return [String] Notifiable path URL to move after opening notification
@@ -327,10 +366,28 @@ module ActivityNotification
327
366
 
328
367
  # Returns if the target subscribes this notification email.
329
368
  # @return [Boolean] If the target subscribes the notification
330
- def email_subscribed?(key)
369
+ def email_subscribed?
331
370
  target.subscribes_to_notification_email?(key)
332
371
  end
333
372
 
373
+ # Returns if the target subscribes this notification email.
374
+ # @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
375
+ # @return [Boolean] If the target subscribes the specified optional target of the notification
376
+ def optional_target_subscribed?(optional_target_name)
377
+ target.subscribes_to_optional_target?(key, optional_target_name)
378
+ end
379
+
380
+ # Returns optional_targets of the notification from configured field or overriden method.
381
+ # @return [Array<ActivityNotification::OptionalTarget::Base>] Array of optional target instances
382
+ def optional_targets
383
+ notifiable.optional_targets(target.to_resources_name, key)
384
+ end
385
+
386
+ # Returns optional_target names of the notification from configured field or overriden method.
387
+ # @return [Array<Symbol>] Array of optional target names
388
+ def optional_target_names
389
+ notifiable.optional_target_names(target.to_resources_name, key)
390
+ end
334
391
 
335
392
  protected
336
393
 
@@ -3,33 +3,73 @@ module ActivityNotification
3
3
  module SubscriptionApi
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ class_methods do
7
+ # Returns key of optional_targets hash from symbol class name of the optional target implementation.
8
+ # @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
9
+ # @return [Symbol] Key of optional_targets hash
10
+ def to_optional_target_key(optional_target_name)
11
+ ("subscribing_to_" + optional_target_name.to_s).to_sym
12
+ end
13
+
14
+ # Returns subscribed_at parameter key of optional_targets hash from symbol class name of the optional target implementation.
15
+ # @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
16
+ # @return [Symbol] Subscribed_at parameter key of optional_targets hash
17
+ def to_optional_target_subscribed_at_key(optional_target_name)
18
+ ("subscribed_to_" + optional_target_name.to_s + "_at").to_sym
19
+ end
20
+
21
+ # Returns unsubscribed_at parameter key of optional_targets hash from symbol class name of the optional target implementation.
22
+ # @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
23
+ # @return [Symbol] Unsubscribed_at parameter key of optional_targets hash
24
+ def to_optional_target_unsubscribed_at_key(optional_target_name)
25
+ ("unsubscribed_to_" + optional_target_name.to_s + "_at").to_sym
26
+ end
27
+ end
28
+
6
29
  # Subscribes to the notification and notification email.
7
30
  #
8
- # @param [Hash] options Options for subscribing notification
31
+ # @param [Hash] options Options for subscribing to the notification
9
32
  # @option options [DateTime] :subscribed_at (Time.current) Time to set to subscribed_at and subscribed_to_email_at of the subscription record
10
33
  # @option options [Boolean] :with_email_subscription (true) If the subscriber also subscribes notification email
34
+ # @option options [Boolean] :with_optional_targets (true) If the subscriber also subscribes optional_targets
11
35
  # @return [Boolean] If successfully updated subscription instance
12
36
  def subscribe(options = {})
13
37
  subscribed_at = options[:subscribed_at] || Time.current
14
38
  with_email_subscription = options.has_key?(:with_email_subscription) ? options[:with_email_subscription] : true
15
- with_email_subscription ?
16
- update(subscribing: true, subscribing_to_email: true, subscribed_at: subscribed_at, subscribed_to_email_at: subscribed_at) :
17
- update(subscribing: true, subscribed_at: subscribed_at)
39
+ with_optional_targets = options.has_key?(:with_optional_targets) ? options[:with_optional_targets] : true
40
+ new_attributes = { subscribing: true, subscribed_at: subscribed_at, optional_targets: optional_targets }
41
+ new_attributes = new_attributes.merge(subscribing_to_email: true, subscribed_to_email_at: subscribed_at) if with_email_subscription
42
+ if with_optional_targets
43
+ optional_target_names.each do |optional_target_name|
44
+ new_attributes[:optional_targets] = new_attributes[:optional_targets].merge(
45
+ Subscription.to_optional_target_key(optional_target_name) => true,
46
+ Subscription.to_optional_target_subscribed_at_key(optional_target_name) => subscribed_at)
47
+ end
48
+ end
49
+ update(new_attributes)
18
50
  end
19
51
 
20
52
  # Unsubscribes to the notification and notification email.
21
53
  #
22
- # @param [Hash] options Options for unsubscribing notification
54
+ # @param [Hash] options Options for unsubscribing to the notification
23
55
  # @option options [DateTime] :unsubscribed_at (Time.current) Time to set to unsubscribed_at and unsubscribed_to_email_at of the subscription record
24
56
  # @return [Boolean] If successfully updated subscription instance
25
57
  def unsubscribe(options = {})
26
58
  unsubscribed_at = options[:unsubscribed_at] || Time.current
27
- update(subscribing: false, subscribing_to_email: false, unsubscribed_at: unsubscribed_at, unsubscribed_to_email_at: unsubscribed_at)
59
+ new_attributes = { subscribing: false, unsubscribed_at: unsubscribed_at,
60
+ subscribing_to_email: false, unsubscribed_to_email_at: unsubscribed_at,
61
+ optional_targets: optional_targets }
62
+ optional_target_names.each do |optional_target_name|
63
+ new_attributes[:optional_targets] = new_attributes[:optional_targets].merge(
64
+ Subscription.to_optional_target_key(optional_target_name) => false,
65
+ Subscription.to_optional_target_unsubscribed_at_key(optional_target_name) => subscribed_at)
66
+ end
67
+ update(new_attributes)
28
68
  end
29
69
 
30
70
  # Subscribes to the notification email.
31
71
  #
32
- # @param [Hash] options Options for subscribing notification email
72
+ # @param [Hash] options Options for subscribing to the notification email
33
73
  # @option options [DateTime] :subscribed_to_email_at (Time.current) Time to set to subscribed_to_email_at of the subscription record
34
74
  # @return [Boolean] If successfully updated subscription instance
35
75
  def subscribe_to_email(options = {})
@@ -39,7 +79,7 @@ module ActivityNotification
39
79
 
40
80
  # Unsubscribes to the notification email.
41
81
  #
42
- # @param [Hash] options Options for unsubscribing notification email
82
+ # @param [Hash] options Options for unsubscribing the notification email
43
83
  # @option options [DateTime] :subscribed_to_email_at (Time.current) Time to set to subscribed_to_email_at of the subscription record
44
84
  # @return [Boolean] If successfully updated subscription instance
45
85
  def unsubscribe_to_email(options = {})
@@ -47,5 +87,50 @@ module ActivityNotification
47
87
  update(subscribing_to_email: false, unsubscribed_to_email_at: unsubscribed_to_email_at)
48
88
  end
49
89
 
90
+ # Returns if the target subscribes to the specified optional target.
91
+ #
92
+ # @param [Symbol] optional_target_name Symbol class name of the optional target implementation (e.g. :amazon_sns, :slack)
93
+ # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record does not configured
94
+ # @return [Boolean] If the target subscribes to the specified optional target
95
+ def subscribing_to_optional_target?(optional_target_name, subscribe_as_default = ActivityNotification.config.subscribe_as_default)
96
+ optional_target_key = Subscription.to_optional_target_key(optional_target_name)
97
+ subscribe_as_default ?
98
+ !optional_targets.has_key?(optional_target_key) || optional_targets[optional_target_key] :
99
+ optional_targets.has_key?(optional_target_key) && optional_targets[optional_target_key]
100
+ end
101
+
102
+ # Subscribes to the specified optional target.
103
+ #
104
+ # @param [String, Symbol] optional_target_name Symbol class name of the optional target implementation (e.g. :amazon_sns, :slack)
105
+ # @param [Hash] options Options for unsubscribing to the specified optional target
106
+ # @option options [DateTime] :subscribed_at (Time.current) Time to set to subscribed_[optional_target_name]_at in optional_targets hash of the subscription record
107
+ # @return [Boolean] If successfully updated subscription instance
108
+ def subscribe_to_optional_target(optional_target_name, options = {})
109
+ subscribed_at = options[:subscribed_at] || Time.current
110
+ update(optional_targets: optional_targets.merge(
111
+ Subscription.to_optional_target_key(optional_target_name) => true,
112
+ Subscription.to_optional_target_subscribed_at_key(optional_target_name) => subscribed_at)
113
+ )
114
+ end
115
+
116
+ # Unsubscribes to the specified optional target.
117
+ #
118
+ # @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
119
+ # @param [Hash] options Options for unsubscribing to the specified optional target
120
+ # @option options [DateTime] :unsubscribed_at (Time.current) Time to set to unsubscribed_[optional_target_name]_at in optional_targets hash of the subscription record
121
+ # @return [Boolean] If successfully updated subscription instance
122
+ def unsubscribe_to_optional_target(optional_target_name, options = {})
123
+ unsubscribed_at = options[:unsubscribed_at] || Time.current
124
+ update(optional_targets: optional_targets.merge(
125
+ Subscription.to_optional_target_key(optional_target_name) => false,
126
+ Subscription.to_optional_target_unsubscribed_at_key(optional_target_name) => unsubscribed_at)
127
+ )
128
+ end
129
+
130
+ # Returns optional_target names of the subscription from optional_targets field.
131
+ # @return [Array<Symbol>] Array of optional target names
132
+ def optional_target_names
133
+ optional_targets.keys.select { |key| key.to_s.start_with?("subscribing_to_") }.map { |key| key.slice(15..-1) }
134
+ end
50
135
  end
51
136
  end
@@ -27,8 +27,10 @@ module ActivityNotification
27
27
  thing.call(ActivityNotification.get_controller, context, *args)
28
28
  elsif thing.arity > 1
29
29
  thing.call(ActivityNotification.get_controller, context)
30
- else
30
+ elsif thing.arity > 0
31
31
  thing.call(context)
32
+ else
33
+ thing.call
32
34
  end
33
35
  when Hash
34
36
  thing.dup.tap do |hash|
@@ -79,8 +81,10 @@ module ActivityNotification
79
81
  when Proc
80
82
  if thing.arity > 1
81
83
  thing.call(self, *args)
82
- else
84
+ elsif thing.arity > 0
83
85
  thing.call(self)
86
+ else
87
+ thing.call
84
88
  end
85
89
  when Hash
86
90
  thing.dup.tap do |hash|
@@ -243,6 +243,28 @@ module ActivityNotification
243
243
  end
244
244
  alias_method :unsubscribe_to_email_path_for, :unsubscribe_to_email_subscription_path_for
245
245
 
246
+ # Returns subscribe_to_optional_target_subscription_path for the target of specified subscription
247
+ #
248
+ # @param [Subscription] subscription Subscription instance
249
+ # @param [Hash] params Request parameters
250
+ # @return [String] subscription_path for the subscription
251
+ # @todo Needs any other better implementation
252
+ def subscribe_to_optional_target_subscription_path_for(subscription, params = {})
253
+ send("subscribe_to_optional_target_#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
254
+ end
255
+ alias_method :subscribe_to_optional_target_path_for, :subscribe_to_optional_target_subscription_path_for
256
+
257
+ # Returns unsubscribe_to_optional_target_subscription_path for the target of specified subscription
258
+ #
259
+ # @param [Subscription] subscription Subscription instance
260
+ # @param [Hash] params Request parameters
261
+ # @return [String] subscription_path for the subscription
262
+ # @todo Needs any other better implementation
263
+ def unsubscribe_to_optional_target_subscription_path_for(subscription, params = {})
264
+ send("unsubscribe_to_optional_target_#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
265
+ end
266
+ alias_method :unsubscribe_to_optional_target_path_for, :unsubscribe_to_optional_target_subscription_path_for
267
+
246
268
  # Returns subscriptions_url for the target
247
269
  #
248
270
  # @param [Object] target Target instance
@@ -307,6 +329,27 @@ module ActivityNotification
307
329
  end
308
330
  alias_method :unsubscribe_to_email_url_for, :unsubscribe_to_email_subscription_url_for
309
331
 
332
+ # Returns subscribe_to_optional_target_subscription_url for the target of specified subscription
333
+ #
334
+ # @param [Subscription] subscription Subscription instance
335
+ # @param [Hash] params Request parameters
336
+ # @return [String] subscription_url for the subscription
337
+ # @todo Needs any other better implementation
338
+ def subscribe_to_optional_target_subscription_url_for(subscription, params = {})
339
+ send("subscribe_to_optional_target_#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
340
+ end
341
+ alias_method :subscribe_to_optional_target_url_for, :subscribe_to_optional_target_subscription_url_for
342
+
343
+ # Returns unsubscribe_to_optional_target_subscription_url for the target of specified subscription
344
+ #
345
+ # @param [Subscription] subscription Subscription instance
346
+ # @param [Hash] params Request parameters
347
+ # @return [String] subscription_url for the subscription
348
+ # @todo Needs any other better implementation
349
+ def unsubscribe_to_optional_target_subscription_url_for(subscription, params = {})
350
+ send("unsubscribe_to_optional_target_#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
351
+ end
352
+ alias_method :unsubscribe_to_optional_target_url_for, :unsubscribe_to_optional_target_subscription_url_for
310
353
 
311
354
  private
312
355
 
@@ -25,7 +25,8 @@ module ActivityNotification
25
25
  :_notification_parameters,
26
26
  :_notification_email_allowed,
27
27
  :_notifiable_path,
28
- :_printable_notifiable_name
28
+ :_printable_notifiable_name,
29
+ :_optional_targets
29
30
  set_notifiable_class_defaults
30
31
  end
31
32
 
@@ -53,6 +54,7 @@ module ActivityNotification
53
54
  self._notification_email_allowed = {}
54
55
  self._notifiable_path = {}
55
56
  self._printable_notifiable_name = {}
57
+ self._optional_targets = {}
56
58
  nil
57
59
  end
58
60
  end
@@ -68,7 +70,8 @@ module ActivityNotification
68
70
  resolved_parameter = resolve_parameter(
69
71
  target_typed_method_name,
70
72
  _notification_targets[cast_to_resources_sym(target_type)],
71
- nil, key)
73
+ nil,
74
+ key)
72
75
  unless resolved_parameter
73
76
  raise NotImplementedError, "You have to implement #{self.class}##{target_typed_method_name} "\
74
77
  "or set :targets in acts_as_notifiable"
@@ -86,7 +89,8 @@ module ActivityNotification
86
89
  resolve_parameter(
87
90
  "notification_group_for_#{cast_to_resources_name(target_type)}",
88
91
  _notification_group[cast_to_resources_sym(target_type)],
89
- nil, key)
92
+ nil,
93
+ key)
90
94
  end
91
95
 
92
96
  # Returns group expiry period of the notifications from configured field or overriden method.
@@ -99,7 +103,8 @@ module ActivityNotification
99
103
  resolve_parameter(
100
104
  "notification_group_expiry_delay_for_#{cast_to_resources_name(target_type)}",
101
105
  _notification_group_expiry_delay[cast_to_resources_sym(target_type)],
102
- nil, key)
106
+ nil,
107
+ key)
103
108
  end
104
109
 
105
110
  # Returns additional notification parameters from configured field or overriden method.
@@ -112,7 +117,8 @@ module ActivityNotification
112
117
  resolve_parameter(
113
118
  "notification_parameters_for_#{cast_to_resources_name(target_type)}",
114
119
  _notification_parameters[cast_to_resources_sym(target_type)],
115
- {}, key)
120
+ {},
121
+ key)
116
122
  end
117
123
 
118
124
  # Returns notifier of the notification from configured field or overriden method.
@@ -125,7 +131,8 @@ module ActivityNotification
125
131
  resolve_parameter(
126
132
  "notifier_for_#{cast_to_resources_name(target_type)}",
127
133
  _notifier[cast_to_resources_sym(target_type)],
128
- nil, key)
134
+ nil,
135
+ key)
129
136
  end
130
137
 
131
138
  # Returns if sending notification email is allowed for the notifiable from configured field or overriden method.
@@ -152,7 +159,8 @@ module ActivityNotification
152
159
  resolved_parameter = resolve_parameter(
153
160
  "notifiable_path_for_#{cast_to_resources_name(target_type)}",
154
161
  _notifiable_path[cast_to_resources_sym(target_type)],
155
- nil, key)
162
+ nil,
163
+ key)
156
164
  unless resolved_parameter
157
165
  begin
158
166
  resolved_parameter = polymorphic_path(self)
@@ -175,6 +183,30 @@ module ActivityNotification
175
183
  target, key)
176
184
  end
177
185
 
186
+ # Returns optional_targets of the notification from configured field or overriden method.
187
+ # This method is able to be overriden.
188
+ #
189
+ # @param [String] target_type Target type to notify
190
+ # @param [String] key Key of the notification
191
+ # @return [Array<ActivityNotification::OptionalTarget::Base>] Array of optional target instances
192
+ def optional_targets(target_type, key = nil)
193
+ resolve_parameter(
194
+ "optional_targets_for_#{cast_to_resources_name(target_type)}",
195
+ _optional_targets[cast_to_resources_sym(target_type)],
196
+ [],
197
+ key)
198
+ end
199
+
200
+ # Returns optional_target names of the notification from configured field or overriden method.
201
+ # This method is able to be overriden.
202
+ #
203
+ # @param [String] target_type Target type to notify
204
+ # @param [String] key Key of the notification
205
+ # @return [Array<Symbol>] Array of optional target names
206
+ def optional_target_names(target_type, key = nil)
207
+ optional_targets(target_type, key).map { |optional_target| optional_target.to_optional_target_name }
208
+ end
209
+
178
210
  # overriding_notification_email_key is the method to override key definition for Mailer
179
211
  # When respond_to?(overriding_notification_email_key) returns true,
180
212
  # Mailer uses overriding_notification_email_key instead of original key.
@@ -188,13 +220,15 @@ module ActivityNotification
188
220
  #
189
221
  # @param [Symbol, String, Class] target_type Type of target
190
222
  # @param [Hash] options Options for notifications
191
- # @option options [String] :key (notifiable.default_notification_key) Key of the notification
192
- # @option options [Object] :group (nil) Group unit of the notifications
193
- # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
194
- # @option options [Object] :notifier (nil) Notifier of the notifications
195
- # @option options [Hash] :parameters ({}) Additional parameters of the notifications
196
- # @option options [Boolean] :send_email (true) Whether it sends notification email
197
- # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
223
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
224
+ # @option options [Object] :group (nil) Group unit of the notifications
225
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
226
+ # @option options [Object] :notifier (nil) Notifier of the notifications
227
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
228
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
229
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
230
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
231
+ # @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
198
232
  # @return [Array<Notificaion>] Array of generated notifications
199
233
  def notify(target_type, options = {})
200
234
  Notification.notify(target_type, self, options)
@@ -206,13 +240,15 @@ module ActivityNotification
206
240
  #
207
241
  # @param [Array<Object>] targets Targets to send notifications
208
242
  # @param [Hash] options Options for notifications
209
- # @option options [String] :key (notifiable.default_notification_key) Key of the notification
210
- # @option options [Object] :group (nil) Group unit of the notifications
211
- # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
212
- # @option options [Object] :notifier (nil) Notifier of the notifications
213
- # @option options [Hash] :parameters ({}) Additional parameters of the notifications
214
- # @option options [Boolean] :send_email (true) Whether it sends notification email
215
- # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
243
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
244
+ # @option options [Object] :group (nil) Group unit of the notifications
245
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
246
+ # @option options [Object] :notifier (nil) Notifier of the notifications
247
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
248
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
249
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
250
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
251
+ # @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
216
252
  # @return [Array<Notificaion>] Array of generated notifications
217
253
  def notify_all(targets, options = {})
218
254
  Notification.notify_all(targets, self, options)
@@ -224,13 +260,15 @@ module ActivityNotification
224
260
  #
225
261
  # @param [Object] target Target to send notifications
226
262
  # @param [Hash] options Options for notifications
227
- # @option options [String] :key (notifiable.default_notification_key) Key of the notification
228
- # @option options [Object] :group (nil) Group unit of the notifications
229
- # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
230
- # @option options [Object] :notifier (nil) Notifier of the notifications
231
- # @option options [Hash] :parameters ({}) Additional parameters of the notifications
232
- # @option options [Boolean] :send_email (true) Whether it sends notification email
233
- # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
263
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
264
+ # @option options [Object] :group (nil) Group unit of the notifications
265
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
266
+ # @option options [Object] :notifier (nil) Notifier of the notifications
267
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
268
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
269
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
270
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
271
+ # @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
234
272
  # @return [Notification] Generated notification instance
235
273
  def notify_to(target, options = {})
236
274
  Notification.notify_to(target, self, options)
@@ -265,6 +303,13 @@ module ActivityNotification
265
303
  end
266
304
  end
267
305
 
306
+ # Remove generated notifications from notification group to new group owner.
307
+ # This method is intended to be called before destroy this notifiable as dependent configuration.
308
+ # @api private
309
+ def remove_generated_notifications_from_group
310
+ generated_notifications_as_notifiable.group_owners_only.each { |n| n.remove_from_group }
311
+ end
312
+
268
313
  # Casts to resources name.
269
314
  # @api private
270
315
  def cast_to_resources_name(target_type)