activity_notification 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +51 -3
  4. data/app/controllers/activity_notification/notifications_controller.rb +1 -1
  5. data/app/controllers/activity_notification/subscriptions_controller.rb +2 -1
  6. data/app/views/activity_notification/notifications/default/_default.html.erb +10 -10
  7. data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +10 -10
  8. data/app/views/activity_notification/notifications/default/_index.html.erb +3 -3
  9. data/app/views/activity_notification/notifications/default/index.html.erb +7 -7
  10. data/app/views/activity_notification/notifications/default/open.js.erb +2 -2
  11. data/app/views/activity_notification/notifications/default/open_all.js.erb +2 -2
  12. data/app/views/activity_notification/notifications/default/show.html.erb +2 -2
  13. data/app/views/activity_notification/optional_targets/default/base/_default.text.erb +1 -1
  14. data/app/views/activity_notification/optional_targets/default/slack/_default.text.erb +1 -1
  15. data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +2 -2
  16. data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +5 -5
  17. data/app/views/activity_notification/subscriptions/default/show.html.erb +1 -1
  18. data/app/views/activity_notification/subscriptions/default/subscribe.js.erb +1 -1
  19. data/app/views/activity_notification/subscriptions/default/subscribe_to_email.js.erb +1 -1
  20. data/app/views/activity_notification/subscriptions/default/subscribe_to_optional_target.js.erb +1 -1
  21. data/app/views/activity_notification/subscriptions/default/unsubscribe.js.erb +1 -1
  22. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_email.js.erb +1 -1
  23. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_optional_target.js.erb +1 -1
  24. data/lib/activity_notification/apis/subscription_api.rb +2 -2
  25. data/lib/activity_notification/controllers/devise_authentication_controller.rb +16 -0
  26. data/lib/activity_notification/helpers/view_helpers.rb +113 -27
  27. data/lib/activity_notification/models/concerns/subscriber.rb +2 -1
  28. data/lib/activity_notification/models/concerns/target.rb +11 -0
  29. data/lib/activity_notification/rails/routes.rb +169 -40
  30. data/lib/activity_notification/roles/acts_as_target.rb +45 -8
  31. data/lib/activity_notification/version.rb +1 -1
  32. data/spec/controllers/notifications_with_devise_controller_spec.rb +15 -0
  33. data/spec/controllers/subscriptions_controller_shared_examples.rb +4 -3
  34. data/spec/controllers/subscriptions_with_devise_controller_spec.rb +15 -0
  35. data/spec/helpers/view_helpers_spec.rb +1 -1
  36. data/spec/rails_app/app/controllers/articles_controller.rb +2 -0
  37. data/spec/rails_app/app/models/admin.rb +2 -0
  38. data/spec/rails_app/app/views/activity_notification/optional_targets/admins/amazon_sns/comment/_default.text.erb +1 -1
  39. data/spec/rails_app/app/views/articles/index.html.erb +36 -32
  40. data/spec/rails_app/app/views/layouts/_header.html.erb +9 -1
  41. data/spec/rails_app/config/routes.rb +5 -0
  42. metadata +2 -2
@@ -188,14 +188,14 @@ module ActivityNotification
188
188
 
189
189
  protected
190
190
 
191
- # Validates subscribing_to_email cannot be true when subscribing isfalse.
191
+ # Validates subscribing_to_email cannot be true when subscribing is false.
192
192
  def subscribing_to_email_cannot_be_true_when_subscribing_is_false
193
193
  if !subscribing && subscribing_to_email?
194
194
  errors.add(:subscribing_to_email, "cannot be true when subscribing is false")
195
195
  end
196
196
  end
197
197
 
198
- # Validates subscribing_to_optional_target cannot be true when subscribing isfalse.
198
+ # Validates subscribing_to_optional_target cannot be true when subscribing is false.
199
199
  def subscribing_to_optional_target_cannot_be_true_when_subscribing_is_false
200
200
  optional_target_names.each do |optional_target_name|
201
201
  if !subscribing && subscribing_to_optional_target?(optional_target_name)
@@ -27,6 +27,22 @@ module ActivityNotification
27
27
  end
28
28
  end
29
29
 
30
+ # Sets @target instance variable from request parameters.
31
+ # This method override super (ActivityNotiication::CommonController#set_target)
32
+ # to set devise authenticated target when the target_id params is not specified.
33
+ # @api protected
34
+ # @return [Object] Target instance (Returns HTTP 400 when request parameters are not enough)
35
+ def set_target
36
+ target_type = params[:target_type]
37
+ if params[:target_id].blank? && params["#{target_type.to_resource_name}_id"].blank?
38
+ target_class = target_type.to_model_class
39
+ current_resource_method_name = "current_#{params[:devise_type].to_resource_name}"
40
+ params[:target_id] = target_class.resolve_current_devise_target(send(current_resource_method_name))
41
+ render(plain: "403 Forbidden: Unauthenticated as default target", status: 403) and return if params[:target_id].blank?
42
+ end
43
+ super
44
+ end
45
+
30
46
  # Authenticate the target of requested notification with authenticated devise resource.
31
47
  # @api protected
32
48
  # @todo Needs to call authenticate method by more secure way
@@ -40,6 +40,8 @@ module ActivityNotification
40
40
  # @option options [String] :notification_layout (nil) Layout template name of the notification index content
41
41
  # @option options [String] :fallback (nil) Fallback template to use when MissingTemplate is raised. Set :text to use i18n text as fallback.
42
42
  # @option options [String] :partial ('index') Partial template name of the partial index
43
+ # @option options [String] :routing_scope (nil) Routing scope for notification and subscription routes
44
+ # @option options [Boolean] :devise_default_routes (false) If links in default views will be handles as devise default routes
43
45
  # @option options [String] :layout (nil) Layout template name of the partial index
44
46
  # @option options [Integer] :limit (nil) Limit to query for notifications
45
47
  # @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
@@ -51,7 +53,7 @@ module ActivityNotification
51
53
  # @option options [String] :filtered_by_key (nil) Key of the notification for filter
52
54
  # @option options [Array] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
53
55
  # @return [String] Rendered view or text as string
54
- def render_notification_of target, options = {}
56
+ def render_notification_of(target, options = {})
55
57
  return unless target.is_a? ActivityNotification::Target
56
58
 
57
59
  # Prepare content for notifications index
@@ -77,7 +79,10 @@ module ActivityNotification
77
79
  # @todo Needs any other better implementation
78
80
  # @todo Must handle devise namespace
79
81
  def notifications_path_for(target, params = {})
80
- send("#{target.to_resource_name}_notifications_path", target, params)
82
+ options = params.dup
83
+ options.delete(:devise_default_routes) ?
84
+ send("#{routing_scope(options)}notifications_path", options) :
85
+ send("#{routing_scope(options)}#{target.to_resource_name}_notifications_path", target, options)
81
86
  end
82
87
 
83
88
  # Returns notification_path for the notification
@@ -88,7 +93,10 @@ module ActivityNotification
88
93
  # @todo Needs any other better implementation
89
94
  # @todo Must handle devise namespace
90
95
  def notification_path_for(notification, params = {})
91
- send("#{notification.target.to_resource_name}_notification_path", notification.target, notification, params)
96
+ options = params.dup
97
+ options.delete(:devise_default_routes) ?
98
+ send("#{routing_scope(options)}notification_path", notification, options) :
99
+ send("#{routing_scope(options)}#{notification.target.to_resource_name}_notification_path", notification.target, notification, options)
92
100
  end
93
101
 
94
102
  # Returns move_notification_path for the target of specified notification
@@ -99,7 +107,10 @@ module ActivityNotification
99
107
  # @todo Needs any other better implementation
100
108
  # @todo Must handle devise namespace
101
109
  def move_notification_path_for(notification, params = {})
102
- send("move_#{notification.target.to_resource_name}_notification_path", notification.target, notification, params)
110
+ options = params.dup
111
+ options.delete(:devise_default_routes) ?
112
+ send("move_#{routing_scope(options)}notification_path", notification, options) :
113
+ send("move_#{routing_scope(options)}#{notification.target.to_resource_name}_notification_path", notification.target, notification, options)
103
114
  end
104
115
 
105
116
  # Returns open_notification_path for the target of specified notification
@@ -110,7 +121,10 @@ module ActivityNotification
110
121
  # @todo Needs any other better implementation
111
122
  # @todo Must handle devise namespace
112
123
  def open_notification_path_for(notification, params = {})
113
- send("open_#{notification.target.to_resource_name}_notification_path", notification.target, notification, params)
124
+ options = params.dup
125
+ options.delete(:devise_default_routes) ?
126
+ send("open_#{routing_scope(options)}notification_path", notification, options) :
127
+ send("open_#{routing_scope(options)}#{notification.target.to_resource_name}_notification_path", notification.target, notification, options)
114
128
  end
115
129
 
116
130
  # Returns open_all_notifications_path for the target
@@ -121,7 +135,10 @@ module ActivityNotification
121
135
  # @todo Needs any other better implementation
122
136
  # @todo Must handle devise namespace
123
137
  def open_all_notifications_path_for(target, params = {})
124
- send("open_all_#{target.to_resource_name}_notifications_path", target, params)
138
+ options = params.dup
139
+ options.delete(:devise_default_routes) ?
140
+ send("open_all_#{routing_scope(options)}notifications_path", options) :
141
+ send("open_all_#{routing_scope(options)}#{target.to_resource_name}_notifications_path", target, options)
125
142
  end
126
143
 
127
144
  # Returns notifications_url for the target
@@ -132,7 +149,10 @@ module ActivityNotification
132
149
  # @todo Needs any other better implementation
133
150
  # @todo Must handle devise namespace
134
151
  def notifications_url_for(target, params = {})
135
- send("#{target.to_resource_name}_notifications_url", target, params)
152
+ options = params.dup
153
+ options.delete(:devise_default_routes) ?
154
+ send("#{routing_scope(options)}notifications_url", options) :
155
+ send("#{routing_scope(options)}#{target.to_resource_name}_notifications_url", target, options)
136
156
  end
137
157
 
138
158
  # Returns notification_url for the target of specified notification
@@ -143,7 +163,10 @@ module ActivityNotification
143
163
  # @todo Needs any other better implementation
144
164
  # @todo Must handle devise namespace
145
165
  def notification_url_for(notification, params = {})
146
- send("#{notification.target.to_resource_name}_notification_url", notification.target, notification, params)
166
+ options = params.dup
167
+ options.delete(:devise_default_routes) ?
168
+ send("#{routing_scope(options)}notification_url", notification, options) :
169
+ send("#{routing_scope(options)}#{notification.target.to_resource_name}_notification_url", notification.target, notification, options)
147
170
  end
148
171
 
149
172
  # Returns move_notification_url for the target of specified notification
@@ -154,7 +177,10 @@ module ActivityNotification
154
177
  # @todo Needs any other better implementation
155
178
  # @todo Must handle devise namespace
156
179
  def move_notification_url_for(notification, params = {})
157
- send("move_#{notification.target.to_resource_name}_notification_url", notification.target, notification, params)
180
+ options = params.dup
181
+ options.delete(:devise_default_routes) ?
182
+ send("move_#{routing_scope(options)}notification_url", notification, options) :
183
+ send("move_#{routing_scope(options)}#{notification.target.to_resource_name}_notification_url", notification.target, notification, options)
158
184
  end
159
185
 
160
186
  # Returns open_notification_url for the target of specified notification
@@ -165,7 +191,10 @@ module ActivityNotification
165
191
  # @todo Needs any other better implementation
166
192
  # @todo Must handle devise namespace
167
193
  def open_notification_url_for(notification, params = {})
168
- send("open_#{notification.target.to_resource_name}_notification_url", notification.target, notification, params)
194
+ options = params.dup
195
+ options.delete(:devise_default_routes) ?
196
+ send("open_#{routing_scope(options)}notification_url", notification, options) :
197
+ send("open_#{routing_scope(options)}#{notification.target.to_resource_name}_notification_url", notification.target, notification, options)
169
198
  end
170
199
 
171
200
  # Returns open_all_notifications_url for the target of specified notification
@@ -176,7 +205,10 @@ module ActivityNotification
176
205
  # @todo Needs any other better implementation
177
206
  # @todo Must handle devise namespace
178
207
  def open_all_notifications_url_for(target, params = {})
179
- send("open_all_#{target.to_resource_name}_notifications_url", target, params)
208
+ options = params.dup
209
+ options.delete(:devise_default_routes) ?
210
+ send("open_all_#{routing_scope(options)}notifications_url", options) :
211
+ send("open_all_#{routing_scope(options)}#{target.to_resource_name}_notifications_url", target, options)
180
212
  end
181
213
 
182
214
  # Returns subscriptions_path for the target
@@ -186,7 +218,10 @@ module ActivityNotification
186
218
  # @return [String] subscriptions_path for the target
187
219
  # @todo Needs any other better implementation
188
220
  def subscriptions_path_for(target, params = {})
189
- send("#{target.to_resource_name}_subscriptions_path", target, params)
221
+ options = params.dup
222
+ options.delete(:devise_default_routes) ?
223
+ send("#{routing_scope(options)}subscriptions_path", options) :
224
+ send("#{routing_scope(options)}#{target.to_resource_name}_subscriptions_path", target, options)
190
225
  end
191
226
 
192
227
  # Returns subscription_path for the subscription
@@ -196,7 +231,10 @@ module ActivityNotification
196
231
  # @return [String] subscription_path for the subscription
197
232
  # @todo Needs any other better implementation
198
233
  def subscription_path_for(subscription, params = {})
199
- send("#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
234
+ options = params.dup
235
+ options.delete(:devise_default_routes) ?
236
+ send("#{routing_scope(options)}subscription_path", subscription, options) :
237
+ send("#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
200
238
  end
201
239
 
202
240
  # Returns subscribe_subscription_path for the target of specified subscription
@@ -206,7 +244,10 @@ module ActivityNotification
206
244
  # @return [String] subscription_path for the subscription
207
245
  # @todo Needs any other better implementation
208
246
  def subscribe_subscription_path_for(subscription, params = {})
209
- send("subscribe_#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
247
+ options = params.dup
248
+ options.delete(:devise_default_routes) ?
249
+ send("subscribe_#{routing_scope(options)}subscription_path", subscription, options) :
250
+ send("subscribe_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
210
251
  end
211
252
  alias_method :subscribe_path_for, :subscribe_subscription_path_for
212
253
 
@@ -217,7 +258,10 @@ module ActivityNotification
217
258
  # @return [String] subscription_path for the subscription
218
259
  # @todo Needs any other better implementation
219
260
  def unsubscribe_subscription_path_for(subscription, params = {})
220
- send("unsubscribe_#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
261
+ options = params.dup
262
+ options.delete(:devise_default_routes) ?
263
+ send("unsubscribe_#{routing_scope(options)}subscription_path", subscription, options) :
264
+ send("unsubscribe_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
221
265
  end
222
266
  alias_method :unsubscribe_path_for, :unsubscribe_subscription_path_for
223
267
 
@@ -228,7 +272,10 @@ module ActivityNotification
228
272
  # @return [String] subscription_path for the subscription
229
273
  # @todo Needs any other better implementation
230
274
  def subscribe_to_email_subscription_path_for(subscription, params = {})
231
- send("subscribe_to_email_#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
275
+ options = params.dup
276
+ options.delete(:devise_default_routes) ?
277
+ send("subscribe_to_email_#{routing_scope(options)}subscription_path", subscription, options) :
278
+ send("subscribe_to_email_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
232
279
  end
233
280
  alias_method :subscribe_to_email_path_for, :subscribe_to_email_subscription_path_for
234
281
 
@@ -239,7 +286,10 @@ module ActivityNotification
239
286
  # @return [String] subscription_path for the subscription
240
287
  # @todo Needs any other better implementation
241
288
  def unsubscribe_to_email_subscription_path_for(subscription, params = {})
242
- send("unsubscribe_to_email_#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, params)
289
+ options = params.dup
290
+ options.delete(:devise_default_routes) ?
291
+ send("unsubscribe_to_email_#{routing_scope(options)}subscription_path", subscription, options) :
292
+ send("unsubscribe_to_email_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
243
293
  end
244
294
  alias_method :unsubscribe_to_email_path_for, :unsubscribe_to_email_subscription_path_for
245
295
 
@@ -250,7 +300,10 @@ module ActivityNotification
250
300
  # @return [String] subscription_path for the subscription
251
301
  # @todo Needs any other better implementation
252
302
  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)
303
+ options = params.dup
304
+ options.delete(:devise_default_routes) ?
305
+ send("subscribe_to_optional_target_#{routing_scope(options)}subscription_path", subscription, options) :
306
+ send("subscribe_to_optional_target_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
254
307
  end
255
308
  alias_method :subscribe_to_optional_target_path_for, :subscribe_to_optional_target_subscription_path_for
256
309
 
@@ -261,7 +314,10 @@ module ActivityNotification
261
314
  # @return [String] subscription_path for the subscription
262
315
  # @todo Needs any other better implementation
263
316
  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)
317
+ options = params.dup
318
+ options.delete(:devise_default_routes) ?
319
+ send("unsubscribe_to_optional_target_#{routing_scope(options)}subscription_path", subscription, options) :
320
+ send("unsubscribe_to_optional_target_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_path", subscription.target, subscription, options)
265
321
  end
266
322
  alias_method :unsubscribe_to_optional_target_path_for, :unsubscribe_to_optional_target_subscription_path_for
267
323
 
@@ -272,7 +328,10 @@ module ActivityNotification
272
328
  # @return [String] subscriptions_url for the target
273
329
  # @todo Needs any other better implementation
274
330
  def subscriptions_url_for(target, params = {})
275
- send("#{target.to_resource_name}_subscriptions_url", target, params)
331
+ options = params.dup
332
+ options.delete(:devise_default_routes) ?
333
+ send("#{routing_scope(options)}subscriptions_url", options) :
334
+ send("#{routing_scope(options)}#{target.to_resource_name}_subscriptions_url", target, options)
276
335
  end
277
336
 
278
337
  # Returns subscription_url for the subscription
@@ -282,7 +341,10 @@ module ActivityNotification
282
341
  # @return [String] subscription_url for the subscription
283
342
  # @todo Needs any other better implementation
284
343
  def subscription_url_for(subscription, params = {})
285
- send("#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
344
+ options = params.dup
345
+ options.delete(:devise_default_routes) ?
346
+ send("#{routing_scope(options)}subscription_url", subscription, options) :
347
+ send("#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
286
348
  end
287
349
 
288
350
  # Returns subscribe_subscription_url for the target of specified subscription
@@ -292,7 +354,10 @@ module ActivityNotification
292
354
  # @return [String] subscription_url for the subscription
293
355
  # @todo Needs any other better implementation
294
356
  def subscribe_subscription_url_for(subscription, params = {})
295
- send("subscribe_#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
357
+ options = params.dup
358
+ options.delete(:devise_default_routes) ?
359
+ send("subscribe_#{routing_scope(options)}subscription_url", subscription, options) :
360
+ send("subscribe_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
296
361
  end
297
362
  alias_method :subscribe_url_for, :subscribe_subscription_url_for
298
363
 
@@ -303,7 +368,10 @@ module ActivityNotification
303
368
  # @return [String] subscription_url for the subscription
304
369
  # @todo Needs any other better implementation
305
370
  def unsubscribe_subscription_url_for(subscription, params = {})
306
- send("unsubscribe_#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
371
+ options = params.dup
372
+ options.delete(:devise_default_routes) ?
373
+ send("unsubscribe_#{routing_scope(options)}subscription_url", subscription, options) :
374
+ send("unsubscribe_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
307
375
  end
308
376
  alias_method :unsubscribe_url_for, :unsubscribe_subscription_url_for
309
377
 
@@ -314,7 +382,10 @@ module ActivityNotification
314
382
  # @return [String] subscription_url for the subscription
315
383
  # @todo Needs any other better implementation
316
384
  def subscribe_to_email_subscription_url_for(subscription, params = {})
317
- send("subscribe_to_email_#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
385
+ options = params.dup
386
+ options.delete(:devise_default_routes) ?
387
+ send("subscribe_to_email_#{routing_scope(options)}subscription_url", subscription, options) :
388
+ send("subscribe_to_email_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
318
389
  end
319
390
  alias_method :subscribe_to_email_url_for, :subscribe_to_email_subscription_url_for
320
391
 
@@ -325,7 +396,10 @@ module ActivityNotification
325
396
  # @return [String] subscription_url for the subscription
326
397
  # @todo Needs any other better implementation
327
398
  def unsubscribe_to_email_subscription_url_for(subscription, params = {})
328
- send("unsubscribe_to_email_#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, params)
399
+ options = params.dup
400
+ options.delete(:devise_default_routes) ?
401
+ send("unsubscribe_to_email_#{routing_scope(options)}subscription_url", subscription, options) :
402
+ send("unsubscribe_to_email_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
329
403
  end
330
404
  alias_method :unsubscribe_to_email_url_for, :unsubscribe_to_email_subscription_url_for
331
405
 
@@ -336,7 +410,10 @@ module ActivityNotification
336
410
  # @return [String] subscription_url for the subscription
337
411
  # @todo Needs any other better implementation
338
412
  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)
413
+ options = params.dup
414
+ options.delete(:devise_default_routes) ?
415
+ send("subscribe_to_optional_target_#{routing_scope(options)}subscription_url", subscription, options) :
416
+ send("subscribe_to_optional_target_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
340
417
  end
341
418
  alias_method :subscribe_to_optional_target_url_for, :subscribe_to_optional_target_subscription_url_for
342
419
 
@@ -347,7 +424,10 @@ module ActivityNotification
347
424
  # @return [String] subscription_url for the subscription
348
425
  # @todo Needs any other better implementation
349
426
  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)
427
+ options = params.dup
428
+ options.delete(:devise_default_routes) ?
429
+ send("unsubscribe_to_optional_target_#{routing_scope(options)}subscription_url", subscription, options) :
430
+ send("unsubscribe_to_optional_target_#{routing_scope(options)}#{subscription.target.to_resource_name}_subscription_url", subscription.target, subscription, options)
351
431
  end
352
432
  alias_method :unsubscribe_to_optional_target_url_for, :unsubscribe_to_optional_target_subscription_url_for
353
433
 
@@ -441,6 +521,12 @@ module ActivityNotification
441
521
  [root, path].map(&:to_s).join('/')
442
522
  end
443
523
 
524
+ # Prepare routing scope from options
525
+ # @api private
526
+ def routing_scope(options = {})
527
+ options[:routing_scope] ? options.delete(:routing_scope).to_s + '_' : ''
528
+ end
529
+
444
530
  end
445
531
 
446
532
  ActionView::Base.class_eval { include ViewHelpers }
@@ -59,7 +59,8 @@ module ActivityNotification
59
59
  subscription.subscribing_to_email? ?
60
60
  subscription.assign_attributes(subscribing_to_email: true, subscribed_to_email_at: created_at) :
61
61
  subscription.assign_attributes(subscribing_to_email: false, unsubscribed_to_email_at: created_at)
62
- optional_targets = subscription.optional_targets
62
+ subscription.optional_targets = (subscription.optional_targets || {}).with_indifferent_access
63
+ optional_targets = {}.with_indifferent_access
63
64
  subscription.optional_target_names.each do |optional_target_name|
64
65
  optional_targets = subscription.subscribing_to_optional_target?(optional_target_name) ?
65
66
  optional_targets.merge(
@@ -20,6 +20,7 @@ module ActivityNotification
20
20
  :_batch_notification_email_allowed,
21
21
  :_notification_subscription_allowed,
22
22
  :_notification_devise_resource,
23
+ :_notification_current_devise_target,
23
24
  :_printable_notification_target_name
24
25
  set_target_class_defaults
25
26
  end
@@ -39,6 +40,7 @@ module ActivityNotification
39
40
  self._batch_notification_email_allowed = ActivityNotification.config.email_enabled
40
41
  self._notification_subscription_allowed = ActivityNotification.config.subscription_enabled
41
42
  self._notification_devise_resource = ->(model) { model }
43
+ self._notification_current_devise_target = ->(current_resource) { current_resource }
42
44
  self._printable_notification_target_name = :printable_name
43
45
  nil
44
46
  end
@@ -130,6 +132,15 @@ module ActivityNotification
130
132
  }.to_h
131
133
  end
132
134
 
135
+ # Resolves current authenticated target by devise authentication from current resource signed in with Devise.
136
+ # This method is able to be overriden.
137
+ #
138
+ # @param [Object] current_resource Current resource signed in with Devise
139
+ # @return [Object] Current authenticated target by devise authentication
140
+ def resolve_current_devise_target(current_resource)
141
+ _notification_current_devise_target.call(current_resource)
142
+ end
143
+
133
144
  # Returns if subscription management is allowed for this target type.
134
145
  # @return [Boolean] If subscription management is allowed for this target type
135
146
  def subscription_enabled?
@@ -26,6 +26,25 @@ module ActionDispatch::Routing
26
26
  # open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
27
27
  # { controller:"activity_notification/notifications", action:"open", target_type:"users" }
28
28
  #
29
+ # You can also configure notification routes with scope like this:
30
+ # scope :myscope, as: :myscope do
31
+ # notify_to :users, routing_scope: :myscope
32
+ # end
33
+ # This routing_scope option creates the needed routes with specified scope like this:
34
+ # # Notification routes
35
+ # myscope_user_notifications GET /myscope/users/:user_id/notifications(.:format)
36
+ # { controller:"activity_notification/notifications", action:"index", target_type:"users", routing_scope: :myscope }
37
+ # myscope_user_notification GET /myscope/users/:user_id/notifications/:id(.:format)
38
+ # { controller:"activity_notification/notifications", action:"show", target_type:"users", routing_scope: :myscope }
39
+ # myscope_user_notification DELETE /myscope/users/:user_id/notifications/:id(.:format)
40
+ # { controller:"activity_notification/notifications", action:"destroy", target_type:"users", routing_scope: :myscope }
41
+ # open_all_myscope_user_notifications POST /myscope/users/:user_id/notifications/open_all(.:format)
42
+ # { controller:"activity_notification/notifications", action:"open_all", target_type:"users", routing_scope: :myscope }
43
+ # move_myscope_user_notification GET /myscope/users/:user_id/notifications/:id/move(.:format)
44
+ # { controller:"activity_notification/notifications", action:"move", target_type:"users", routing_scope: :myscope }
45
+ # open_myscope_user_notification POST /myscope/users/:user_id/notifications/:id/open(.:format)
46
+ # { controller:"activity_notification/notifications", action:"open", target_type:"users", routing_scope: :myscope }
47
+ #
29
48
  # When you use devise authentication and you want make notification targets assciated with devise,
30
49
  # you can create as follows in your routes:
31
50
  # notify_to :users, with_devise: :users
@@ -44,6 +63,23 @@ module ActionDispatch::Routing
44
63
  # open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
45
64
  # { controller:"activity_notification/notifications_with_devise", action:"open", target_type:"users", devise_type:"users" }
46
65
  #
66
+ # When you use with_devise option and you want to make simple default routes as follows, you can use devise_default_routes option:
67
+ # notify_to :users, with_devise: :users, devise_default_routes: true
68
+ # These with_devise and devise_default_routes options create the needed routes assciated with authenticated devise resource as the default target
69
+ # # Notification with default devise routes
70
+ # user_notifications GET /notifications(.:format)
71
+ # { controller:"activity_notification/notifications_with_devise", action:"index", target_type:"users", devise_type:"users" }
72
+ # user_notification GET /notifications/:id(.:format)
73
+ # { controller:"activity_notification/notifications_with_devise", action:"show", target_type:"users", devise_type:"users" }
74
+ # user_notification DELETE /notifications/:id(.:format)
75
+ # { controller:"activity_notification/notifications_with_devise", action:"destroy", target_type:"users", devise_type:"users" }
76
+ # open_all_user_notifications POST /notifications/open_all(.:format)
77
+ # { controller:"activity_notification/notifications_with_devise", action:"open_all", target_type:"users", devise_type:"users" }
78
+ # move_user_notification GET /notifications/:id/move(.:format)
79
+ # { controller:"activity_notification/notifications_with_devise", action:"move", target_type:"users", devise_type:"users" }
80
+ # open_user_notification POST /notifications/:id/open(.:format)
81
+ # { controller:"activity_notification/notifications_with_devise", action:"open", target_type:"users", devise_type:"users" }
82
+ #
47
83
  # When you would like to define subscription management paths with notification paths,
48
84
  # you can create as follows in your routes:
49
85
  # notify_to :users, with_subscription: true
@@ -60,32 +96,36 @@ module ActionDispatch::Routing
60
96
  # notify_to :users, with_devise: :users
61
97
  # @example Define notification paths including subscription paths
62
98
  # notify_to :users, with_subscription: true
99
+ # @example Integrated with Devise authentication as simple default routes including subscription management
100
+ # notify_to :users, with_devise: :users, devise_default_routes: true, with_subscription: true
101
+ # @example Integrated with Devise authentication as simple default routes with scope including subscription management
102
+ # scope :myscope, as: :myscope do
103
+ # notify_to :myscope, with_devise: :users, devise_default_routes: true, with_subscription: true, routing_scope: :myscope
104
+ # end
63
105
  #
64
106
  # @overload notify_to(*resources, *options)
65
107
  # @param [Symbol] resources Resources to notify
66
- # @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
67
- # @option options [Hash|Boolean] :with_subscription (false) Subscription path options to define subscription management paths with notification paths. Calls subscribed_by routing when truthy value is passed as this option.
68
- # @option options [String] :model (:notifications) Model name of notifications
69
- # @option options [String] :controller ("activity_notification/notifications" | activity_notification/notifications_with_devise") :controller option as resources routing
70
- # @option options [Symbol] :as (nil) :as option as resources routing
71
- # @option options [Array] :only (nil) :only option as resources routing
72
- # @option options [Array] :except (nil) :except option as resources routing
108
+ # @option options [String] :routing_scope (nil) Routing scope for notification routes
109
+ # @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
110
+ # @option options [Boolean] :devise_default_routes (false) Whether you will create routes as device default routes assciated with authenticated devise resource as the default target
111
+ # @option options [Hash|Boolean] :with_subscription (false) Subscription path options to define subscription management paths with notification paths. Calls subscribed_by routing when truthy value is passed as this option.
112
+ # @option options [String] :model (:notifications) Model name of notifications
113
+ # @option options [String] :controller ("activity_notification/notifications" | activity_notification/notifications_with_devise") :controller option as resources routing
114
+ # @option options [Symbol] :as (nil) :as option as resources routing
115
+ # @option options [Array] :only (nil) :only option as resources routing
116
+ # @option options [Array] :except (nil) :except option as resources routing
73
117
  # @return [ActionDispatch::Routing::Mapper] Routing mapper instance
74
118
  def notify_to(*resources)
75
119
  options = create_options(:notifications, resources.extract_options!, [:new, :create, :edit, :update])
76
120
 
77
121
  resources.each do |target|
78
- self.resources target, only: :none do
79
- options[:defaults] = { target_type: target.to_s }.merge(options[:devise_defaults])
80
- resources_options = options.select { |key, _| [:with_devise, :with_subscription, :subscription_option, :model, :devise_defaults].exclude? key }
81
- self.resources options[:model], resources_options do
82
- collection do
83
- post :open_all unless ignore_path?(:open_all, options)
84
- end
85
- member do
86
- get :move unless ignore_path?(:move, options)
87
- post :open unless ignore_path?(:open, options)
88
- end
122
+ options[:defaults] = { target_type: target.to_s }.merge(options[:devise_defaults])
123
+ resources_options = options.select { |key, _| [:with_devise, :devise_default_routes, :with_subscription, :subscription_option, :model, :devise_defaults].exclude? key }
124
+ if options[:with_devise].present? && options[:devise_default_routes].present?
125
+ create_notification_routes options, resources_options
126
+ else
127
+ self.resources target, only: :none do
128
+ create_notification_routes options, resources_options
89
129
  end
90
130
  end
91
131
 
@@ -125,9 +165,36 @@ module ActionDispatch::Routing
125
165
  # unsubscribe_to_optional_target_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
126
166
  # { controller:"activity_notification/subscriptions", action:"unsubscribe_to_optional_target", target_type:"users" }
127
167
  #
168
+ # You can also configure notification routes with scope like this:
169
+ # scope :myscope, as: :myscope do
170
+ # subscribed_by :users, routing_scope: :myscope
171
+ # end
172
+ # This routing_scope option creates the needed routes with specified scope like this:
173
+ # # Subscription routes
174
+ # myscope_user_subscriptions GET /myscope/users/:user_id/subscriptions(.:format)
175
+ # { controller:"activity_notification/subscriptions", action:"index", target_type:"users", routing_scope: :myscope }
176
+ # myscope_user_subscription GET /myscope/users/:user_id/subscriptions/:id(.:format)
177
+ # { controller:"activity_notification/subscriptions", action:"show", target_type:"users", routing_scope: :myscope }
178
+ # open_all_myscope_user_subscriptions POST /myscope/users/:user_id/subscriptions(.:format)
179
+ # { controller:"activity_notification/subscriptions", action:"create", target_type:"users", routing_scope: :myscope }
180
+ # myscope_user_subscription DELETE /myscope/users/:user_id/subscriptions/:id(.:format)
181
+ # { controller:"activity_notification/subscriptions", action:"destroy", target_type:"users", routing_scope: :myscope }
182
+ # subscribe_myscope_user_subscription POST /myscope/users/:user_id/subscriptions/:id/subscribe(.:format)
183
+ # { controller:"activity_notification/subscriptions", action:"subscribe", target_type:"users", routing_scope: :myscope }
184
+ # unsubscribe_myscope_user_subscription POST /myscope/users/:user_id/subscriptions/:id/unsubscribe(.:format)
185
+ # { controller:"activity_notification/subscriptions", action:"unsubscribe", target_type:"users", routing_scope: :myscope }
186
+ # subscribe_to_email_myscope_user_subscription POST /myscope/users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
187
+ # { controller:"activity_notification/subscriptions", action:"subscribe_to_email", target_type:"users", routing_scope: :myscope }
188
+ # unsubscribe_to_email_myscope_user_subscription POST /myscope/users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
189
+ # { controller:"activity_notification/subscriptions", action:"unsubscribe_to_email", target_type:"users", routing_scope: :myscope }
190
+ # subscribe_to_optional_target_myscope_user_subscription POST /myscope/users/:user_id/subscriptions/:id/subscribe_to_optional_target(.:format)
191
+ # { controller:"activity_notification/subscriptions", action:"subscribe_to_optional_target", target_type:"users", routing_scope: :myscope }
192
+ # unsubscribe_to_optional_target_myscope_user_subscription POST /myscope/users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
193
+ # { controller:"activity_notification/subscriptions", action:"unsubscribe_to_optional_target", target_type:"users", routing_scope: :myscope }
194
+ #
128
195
  # When you use devise authentication and you want make subscription targets assciated with devise,
129
196
  # you can create as follows in your routes:
130
- # notify_to :users, with_devise: :users
197
+ # subscribed_by :users, with_devise: :users
131
198
  # This with_devise option creates the needed routes assciated with devise authentication:
132
199
  # # Subscription with devise routes
133
200
  # user_subscriptions GET /users/:user_id/subscriptions(.:format)
@@ -151,6 +218,31 @@ module ActionDispatch::Routing
151
218
  # unsubscribe_to_optional_target_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
152
219
  # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_optional_target", target_type:"users", devise_type:"users" }
153
220
  #
221
+ # When you use with_devise option and you want to make simple default routes as follows, you can use devise_default_routes option:
222
+ # subscribed_by :users, with_devise: :users, devise_default_routes: true
223
+ # These with_devise and devise_default_routes options create the needed routes assciated with authenticated devise resource as the default target
224
+ # # Subscription with devise routes
225
+ # user_subscriptions GET /subscriptions(.:format)
226
+ # { controller:"activity_notification/subscriptions_with_devise", action:"index", target_type:"users", devise_type:"users" }
227
+ # user_subscription GET /subscriptions/:id(.:format)
228
+ # { controller:"activity_notification/subscriptions_with_devise", action:"show", target_type:"users", devise_type:"users" }
229
+ # open_all_user_subscriptions POST /subscriptions(.:format)
230
+ # { controller:"activity_notification/subscriptions_with_devise", action:"create", target_type:"users", devise_type:"users" }
231
+ # user_subscription DELETE /subscriptions/:id(.:format)
232
+ # { controller:"activity_notification/subscriptions_with_devise", action:"destroy", target_type:"users", devise_type:"users" }
233
+ # subscribe_user_subscription POST /subscriptions/:id/subscribe(.:format)
234
+ # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe", target_type:"users", devise_type:"users" }
235
+ # unsubscribe_user_subscription POST /subscriptions/:id/unsubscribe(.:format)
236
+ # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe", target_type:"users", devise_type:"users" }
237
+ # subscribe_to_email_user_subscription POST /subscriptions/:id/subscribe_to_email(.:format)
238
+ # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe_to_email", target_type:"users", devise_type:"users" }
239
+ # unsubscribe_to_email_user_subscription POST /subscriptions/:id/unsubscribe_to_email(.:format)
240
+ # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_email", target_type:"users", devise_type:"users" }
241
+ # subscribe_to_optional_target_user_subscription POST /subscriptions/:id/subscribe_to_optional_target(.:format)
242
+ # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe_to_optional_target", target_type:"users", devise_type:"users" }
243
+ # unsubscribe_to_optional_target_user_subscription POST /subscriptions/:id/unsubscribe_to_optional_target(.:format)
244
+ # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_optional_target", target_type:"users", devise_type:"users" }
245
+ #
154
246
  # @example Define subscribed_by in config/routes.rb
155
247
  # subscribed_by :users
156
248
  # @example Define subscribed_by with options
@@ -160,29 +252,26 @@ module ActionDispatch::Routing
160
252
  #
161
253
  # @overload subscribed_by(*resources, *options)
162
254
  # @param [Symbol] resources Resources to notify
163
- # @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
164
- # @option options [String] :model (:subscriptions) Model name of subscriptions
165
- # @option options [String] :controller ("activity_notification/subscriptions" | activity_notification/subscriptions_with_devise") :controller option as resources routing
166
- # @option options [Symbol] :as (nil) :as option as resources routing
167
- # @option options [Array] :only (nil) :only option as resources routing
168
- # @option options [Array] :except (nil) :except option as resources routing
255
+ # @option options [String] :routing_scope (nil) Routing scope for subscription routes
256
+ # @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
257
+ # @option options [Boolean] :devise_default_routes (false) Whether you will create routes as device default routes assciated with authenticated devise resource as the default target
258
+ # @option options [String] :model (:subscriptions) Model name of subscriptions
259
+ # @option options [String] :controller ("activity_notification/subscriptions" | activity_notification/subscriptions_with_devise") :controller option as resources routing
260
+ # @option options [Symbol] :as (nil) :as option as resources routing
261
+ # @option options [Array] :only (nil) :only option as resources routing
262
+ # @option options [Array] :except (nil) :except option as resources routing
169
263
  # @return [ActionDispatch::Routing::Mapper] Routing mapper instance
170
264
  def subscribed_by(*resources)
171
265
  options = create_options(:subscriptions, resources.extract_options!, [:new, :edit, :update])
172
266
 
173
267
  resources.each do |target|
174
- self.resources target, only: :none do
175
- options[:defaults] = { target_type: target.to_s }.merge(options[:devise_defaults])
176
- resources_options = options.select { |key, _| [:with_devise, :model, :devise_defaults].exclude? key }
177
- self.resources options[:model], resources_options do
178
- member do
179
- post :subscribe unless ignore_path?(:subscribe, options)
180
- post :unsubscribe unless ignore_path?(:unsubscribe, options)
181
- post :subscribe_to_email unless ignore_path?(:subscribe_to_email, options)
182
- post :unsubscribe_to_email unless ignore_path?(:unsubscribe_to_email, options)
183
- post :subscribe_to_optional_target unless ignore_path?(:subscribe_to_optional_target, options)
184
- post :unsubscribe_to_optional_target unless ignore_path?(:unsubscribe_to_optional_target, options)
185
- end
268
+ options[:defaults] = { target_type: target.to_s }.merge(options[:devise_defaults])
269
+ resources_options = options.select { |key, _| [:with_devise, :devise_default_routes, :model, :devise_defaults].exclude? key }
270
+ if options[:with_devise].present? && options[:devise_default_routes].present?
271
+ create_subscription_routes options, resources_options
272
+ else
273
+ self.resources target, only: :none do
274
+ create_subscription_routes options, resources_options
186
275
  end
187
276
  end
188
277
  end
@@ -202,14 +291,16 @@ module ActionDispatch::Routing
202
291
  false
203
292
  end
204
293
 
205
- # Create options fo routing
294
+ # Create options for routing
206
295
  # @api private
207
296
  # @todo Check resources if it includes target module
208
297
  # @todo Check devise configuration in model
209
298
  # @todo Support other options like :as, :path_prefix, :path_names ...
210
299
  #
211
300
  # @param [Symbol] resource Name of the resource model
212
- # @return [Boolean] Whether action path is ignored
301
+ # @param [Hash] options Passed options from notify_to or subscribed_by
302
+ # @param [Hash] except_actions Actions in [:index, :show, :new, :create, :edit, :update, :destroy] to remove routes
303
+ # @return [Hash] Options to create routes
213
304
  def create_options(resource, options = {}, except_actions = [])
214
305
  # Check resources if it includes target module
215
306
  resources_name = resource.to_s.pluralize.underscore
@@ -219,6 +310,7 @@ module ActionDispatch::Routing
219
310
  options[:as] ||= resources_name
220
311
  # Check devise configuration in model
221
312
  options[:devise_defaults] = { devise_type: options[:with_devise].to_s }
313
+ options[:devise_defaults] = options[:devise_defaults].merge(options.slice(:devise_default_routes))
222
314
  else
223
315
  options[:controller] ||= "activity_notification/#{resources_name}"
224
316
  options[:devise_defaults] = {}
@@ -226,11 +318,48 @@ module ActionDispatch::Routing
226
318
  (options[:except] ||= []).concat(except_actions)
227
319
  if options[:with_subscription].present?
228
320
  options[:subscription_option] = (options[:with_subscription].is_a?(Hash) ? options[:with_subscription] : {})
229
- .merge(with_devise: options[:with_devise])
321
+ .merge(options.slice(:with_devise, :devise_default_routes, :routing_scope))
230
322
  end
231
323
  # Support other options like :as, :path_prefix, :path_names ...
232
324
  options
233
325
  end
234
326
 
327
+ # Create routes for notifications
328
+ # @api private
329
+ #
330
+ # @param [Symbol] resource Name of the resource model
331
+ # @param [Hash] options Passed options from notify_to
332
+ # @param [Hash] resources_options Options to send resources method
333
+ def create_notification_routes(options = {}, resources_options = [])
334
+ self.resources options[:model], resources_options do
335
+ collection do
336
+ post :open_all unless ignore_path?(:open_all, options)
337
+ end
338
+ member do
339
+ get :move unless ignore_path?(:move, options)
340
+ post :open unless ignore_path?(:open, options)
341
+ end
342
+ end
343
+ end
344
+
345
+ # Create routes for subscriptions
346
+ # @api private
347
+ #
348
+ # @param [Symbol] resource Name of the resource model
349
+ # @param [Hash] options Passed options from subscribed_by
350
+ # @param [Hash] resources_options Options to send resources method
351
+ def create_subscription_routes(options = {}, resources_options = [])
352
+ self.resources options[:model], resources_options do
353
+ member do
354
+ post :subscribe unless ignore_path?(:subscribe, options)
355
+ post :unsubscribe unless ignore_path?(:unsubscribe, options)
356
+ post :subscribe_to_email unless ignore_path?(:subscribe_to_email, options)
357
+ post :unsubscribe_to_email unless ignore_path?(:unsubscribe_to_email, options)
358
+ post :subscribe_to_optional_target unless ignore_path?(:subscribe_to_optional_target, options)
359
+ post :unsubscribe_to_optional_target unless ignore_path?(:unsubscribe_to_optional_target, options)
360
+ end
361
+ end
362
+ end
363
+
235
364
  end
236
365
  end