activity_notification 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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)