activity_notification 2.0.0 → 2.1.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +22 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  4. data/.github/pull_request_template.md +13 -0
  5. data/.gitignore +10 -3
  6. data/.travis.yml +6 -5
  7. data/CHANGELOG.md +22 -0
  8. data/Gemfile +8 -2
  9. data/Procfile +1 -1
  10. data/README.md +153 -1510
  11. data/activity_notification.gemspec +4 -1
  12. data/app/channels/activity_notification/notification_api_channel.rb +12 -0
  13. data/app/channels/activity_notification/notification_api_with_devise_channel.rb +46 -0
  14. data/app/channels/activity_notification/notification_channel.rb +1 -1
  15. data/app/channels/activity_notification/notification_with_devise_channel.rb +1 -1
  16. data/app/controllers/activity_notification/apidocs_controller.rb +75 -0
  17. data/app/controllers/activity_notification/notifications_api_controller.rb +143 -0
  18. data/app/controllers/activity_notification/notifications_api_with_devise_controller.rb +7 -0
  19. data/app/controllers/activity_notification/notifications_controller.rb +79 -53
  20. data/app/controllers/activity_notification/subscriptions_api_controller.rb +197 -0
  21. data/app/controllers/activity_notification/subscriptions_api_with_devise_controller.rb +7 -0
  22. data/app/controllers/activity_notification/subscriptions_controller.rb +78 -69
  23. data/app/views/activity_notification/notifications/default/_default.html.erb +18 -18
  24. data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +14 -14
  25. data/app/views/activity_notification/notifications/default/index.html.erb +6 -6
  26. data/app/views/activity_notification/optional_targets/default/action_cable_channel/_default.html.erb +176 -0
  27. data/app/views/activity_notification/subscriptions/default/_form.html.erb +1 -1
  28. data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +3 -31
  29. data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +7 -7
  30. data/app/views/activity_notification/subscriptions/default/index.html.erb +11 -7
  31. data/bin/deploy_on_heroku.sh +3 -1
  32. data/docs/CODE_OF_CONDUCT.md +76 -0
  33. data/docs/CONTRIBUTING.md +36 -0
  34. data/docs/Functions.md +1130 -0
  35. data/docs/Setup.md +674 -0
  36. data/docs/Testing.md +148 -0
  37. data/gemfiles/Gemfile.rails-4.2 +3 -0
  38. data/gemfiles/Gemfile.rails-5.0 +3 -0
  39. data/gemfiles/Gemfile.rails-5.1 +3 -0
  40. data/gemfiles/Gemfile.rails-5.2 +3 -0
  41. data/gemfiles/{Gemfile.rails-6.0.rc → Gemfile.rails-6.0} +5 -3
  42. data/lib/activity_notification.rb +13 -1
  43. data/lib/activity_notification/apis/notification_api.rb +29 -92
  44. data/lib/activity_notification/apis/subscription_api.rb +20 -8
  45. data/lib/activity_notification/apis/swagger.rb +6 -0
  46. data/lib/activity_notification/config.rb +41 -21
  47. data/lib/activity_notification/controllers/common_api_controller.rb +30 -0
  48. data/lib/activity_notification/controllers/common_controller.rb +44 -20
  49. data/lib/activity_notification/controllers/concerns/swagger/error_responses.rb +55 -0
  50. data/lib/activity_notification/controllers/concerns/swagger/notifications_api.rb +273 -0
  51. data/lib/activity_notification/controllers/concerns/swagger/notifications_parameters.rb +92 -0
  52. data/lib/activity_notification/controllers/concerns/swagger/subscriptions_api.rb +405 -0
  53. data/lib/activity_notification/controllers/concerns/swagger/subscriptions_parameters.rb +50 -0
  54. data/lib/activity_notification/controllers/devise_authentication_controller.rb +7 -6
  55. data/lib/activity_notification/gem_version.rb +14 -0
  56. data/lib/activity_notification/helpers/errors.rb +2 -0
  57. data/lib/activity_notification/helpers/view_helpers.rb +4 -0
  58. data/lib/activity_notification/mailers/helpers.rb +17 -10
  59. data/lib/activity_notification/models/concerns/notifiable.rb +26 -10
  60. data/lib/activity_notification/models/concerns/subscriber.rb +12 -1
  61. data/lib/activity_notification/models/concerns/swagger/error_schema.rb +36 -0
  62. data/lib/activity_notification/models/concerns/swagger/notification_schema.rb +209 -0
  63. data/lib/activity_notification/models/concerns/swagger/subscription_schema.rb +162 -0
  64. data/lib/activity_notification/models/concerns/target.rb +36 -10
  65. data/lib/activity_notification/models/notification.rb +1 -0
  66. data/lib/activity_notification/models/subscription.rb +1 -0
  67. data/lib/activity_notification/optional_targets/action_cable_api_channel.rb +69 -0
  68. data/lib/activity_notification/optional_targets/action_cable_channel.rb +68 -0
  69. data/lib/activity_notification/optional_targets/base.rb +7 -13
  70. data/lib/activity_notification/orm/active_record/notification.rb +17 -1
  71. data/lib/activity_notification/orm/active_record/subscription.rb +1 -1
  72. data/lib/activity_notification/orm/dynamoid.rb +28 -0
  73. data/lib/activity_notification/orm/dynamoid/extension.rb +79 -1
  74. data/lib/activity_notification/orm/dynamoid/notification.rb +1 -1
  75. data/lib/activity_notification/orm/dynamoid/subscription.rb +1 -1
  76. data/lib/activity_notification/orm/mongoid.rb +22 -0
  77. data/lib/activity_notification/orm/mongoid/notification.rb +17 -1
  78. data/lib/activity_notification/orm/mongoid/subscription.rb +1 -1
  79. data/lib/activity_notification/rails/routes.rb +132 -48
  80. data/lib/activity_notification/renderable.rb +13 -2
  81. data/lib/activity_notification/roles/acts_as_notifiable.rb +38 -20
  82. data/lib/activity_notification/version.rb +1 -1
  83. data/lib/generators/activity_notification/controllers_generator.rb +2 -1
  84. data/lib/generators/templates/activity_notification.rb +8 -0
  85. data/lib/generators/templates/controllers/notifications_api_controller.rb +31 -0
  86. data/lib/generators/templates/controllers/notifications_api_with_devise_controller.rb +31 -0
  87. data/lib/generators/templates/controllers/notifications_controller.rb +1 -37
  88. data/lib/generators/templates/controllers/notifications_with_devise_controller.rb +1 -45
  89. data/lib/generators/templates/controllers/subscriptions_api_controller.rb +61 -0
  90. data/lib/generators/templates/controllers/subscriptions_api_with_devise_controller.rb +61 -0
  91. data/lib/generators/templates/controllers/subscriptions_controller.rb +14 -37
  92. data/lib/generators/templates/controllers/subscriptions_with_devise_controller.rb +14 -45
  93. data/lib/generators/templates/models/README +8 -4
  94. data/lib/generators/templates/models/notification.rb +1 -1
  95. data/lib/generators/templates/models/subscription.rb +1 -1
  96. data/package.json +8 -0
  97. data/spec/channels/notification_api_channel_shared_examples.rb +59 -0
  98. data/spec/channels/notification_api_channel_spec.rb +51 -0
  99. data/spec/channels/notification_api_with_devise_channel_spec.rb +78 -0
  100. data/spec/concerns/apis/notification_api_spec.rb +37 -2
  101. data/spec/concerns/models/notifiable_spec.rb +64 -0
  102. data/spec/concerns/models/subscriber_spec.rb +13 -16
  103. data/spec/concerns/models/target_spec.rb +32 -0
  104. data/spec/concerns/renderable_spec.rb +2 -2
  105. data/spec/controllers/controller_spec_utility.rb +136 -0
  106. data/spec/controllers/notifications_api_controller_shared_examples.rb +506 -0
  107. data/spec/controllers/notifications_api_controller_spec.rb +19 -0
  108. data/spec/controllers/notifications_api_with_devise_controller_spec.rb +60 -0
  109. data/spec/controllers/notifications_controller_shared_examples.rb +54 -79
  110. data/spec/controllers/notifications_controller_spec.rb +1 -2
  111. data/spec/controllers/notifications_with_devise_controller_spec.rb +3 -12
  112. data/spec/controllers/subscriptions_api_controller_shared_examples.rb +750 -0
  113. data/spec/controllers/subscriptions_api_controller_spec.rb +19 -0
  114. data/spec/controllers/subscriptions_api_with_devise_controller_spec.rb +60 -0
  115. data/spec/controllers/subscriptions_controller_shared_examples.rb +94 -121
  116. data/spec/controllers/subscriptions_controller_spec.rb +1 -2
  117. data/spec/controllers/subscriptions_with_devise_controller_spec.rb +3 -12
  118. data/spec/helpers/view_helpers_spec.rb +4 -11
  119. data/spec/mailers/mailer_spec.rb +41 -0
  120. data/spec/models/notification_spec.rb +17 -0
  121. data/spec/models/subscription_spec.rb +0 -13
  122. data/spec/optional_targets/action_cable_api_channel_spec.rb +37 -0
  123. data/spec/optional_targets/action_cable_channel_spec.rb +44 -0
  124. data/spec/optional_targets/amazon_sns_spec.rb +0 -2
  125. data/spec/optional_targets/slack_spec.rb +0 -2
  126. data/spec/rails_app/Rakefile +9 -0
  127. data/spec/rails_app/app/assets/config/manifest.js +3 -0
  128. data/spec/rails_app/app/assets/images/.keep +0 -0
  129. data/spec/rails_app/app/controllers/admins_controller.rb +21 -0
  130. data/spec/rails_app/app/controllers/application_controller.rb +1 -1
  131. data/spec/rails_app/app/controllers/articles_controller.rb +6 -3
  132. data/spec/rails_app/app/controllers/spa_controller.rb +7 -0
  133. data/spec/rails_app/app/controllers/users/notifications_controller.rb +0 -65
  134. data/spec/rails_app/app/controllers/users/notifications_with_devise_controller.rb +0 -73
  135. data/spec/rails_app/app/controllers/users/subscriptions_controller.rb +0 -77
  136. data/spec/rails_app/app/controllers/users/subscriptions_with_devise_controller.rb +0 -85
  137. data/spec/rails_app/app/controllers/users_controller.rb +21 -0
  138. data/spec/rails_app/app/javascript/App.vue +104 -0
  139. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +83 -0
  140. data/spec/rails_app/app/javascript/components/Top.vue +99 -0
  141. data/spec/rails_app/app/javascript/components/notifications/Index.vue +200 -0
  142. data/spec/rails_app/app/javascript/components/notifications/Notification.vue +133 -0
  143. data/spec/rails_app/app/javascript/components/notifications/NotificationContent.vue +122 -0
  144. data/spec/rails_app/app/javascript/components/subscriptions/Index.vue +279 -0
  145. data/spec/rails_app/app/javascript/components/subscriptions/NewSubscription.vue +112 -0
  146. data/spec/rails_app/app/javascript/components/subscriptions/NotificationKey.vue +141 -0
  147. data/spec/rails_app/app/javascript/components/subscriptions/Subscription.vue +226 -0
  148. data/spec/rails_app/app/javascript/config/development.js +5 -0
  149. data/spec/rails_app/app/javascript/config/environment.js +7 -0
  150. data/spec/rails_app/app/javascript/config/production.js +5 -0
  151. data/spec/rails_app/app/javascript/config/test.js +5 -0
  152. data/spec/rails_app/app/javascript/packs/application.js +18 -0
  153. data/spec/rails_app/app/javascript/packs/spa.js +11 -0
  154. data/spec/rails_app/app/javascript/store/auth.js +37 -0
  155. data/spec/rails_app/app/models/admin.rb +16 -15
  156. data/spec/rails_app/app/models/article.rb +26 -21
  157. data/spec/rails_app/app/models/comment.rb +24 -71
  158. data/spec/rails_app/app/models/user.rb +43 -20
  159. data/spec/rails_app/app/views/activity_notification/notifications/default/article/_update.html.erb +146 -0
  160. data/spec/rails_app/app/views/articles/index.html.erb +51 -7
  161. data/spec/rails_app/app/views/articles/show.html.erb +1 -1
  162. data/spec/rails_app/app/views/layouts/_header.html.erb +8 -10
  163. data/spec/rails_app/app/views/spa/index.html.erb +2 -0
  164. data/spec/rails_app/babel.config.js +72 -0
  165. data/spec/rails_app/bin/webpack +18 -0
  166. data/spec/rails_app/bin/webpack-dev-server +18 -0
  167. data/spec/rails_app/config/application.rb +15 -2
  168. data/spec/rails_app/config/environment.rb +2 -1
  169. data/spec/rails_app/config/environments/development.rb +5 -0
  170. data/spec/rails_app/config/environments/production.rb +3 -0
  171. data/spec/rails_app/config/environments/test.rb +5 -0
  172. data/spec/rails_app/config/initializers/activity_notification.rb +8 -0
  173. data/spec/rails_app/config/initializers/devise_token_auth.rb +55 -0
  174. data/spec/rails_app/config/initializers/mysql.rb +9 -0
  175. data/spec/rails_app/config/locales/activity_notification.en.yml +2 -2
  176. data/spec/rails_app/config/routes.rb +33 -1
  177. data/spec/rails_app/config/webpack/development.js +5 -0
  178. data/spec/rails_app/config/webpack/environment.js +7 -0
  179. data/spec/rails_app/config/webpack/loaders/vue.js +6 -0
  180. data/spec/rails_app/config/webpack/production.js +5 -0
  181. data/spec/rails_app/config/webpack/test.js +5 -0
  182. data/spec/rails_app/config/webpacker.yml +97 -0
  183. data/spec/rails_app/db/migrate/20191201000000_add_tokens_to_users.rb +10 -0
  184. data/spec/rails_app/db/schema.rb +4 -1
  185. data/spec/rails_app/db/seeds.rb +1 -0
  186. data/spec/rails_app/lib/custom_optional_targets/raise_error.rb +14 -0
  187. data/spec/rails_app/package.json +23 -0
  188. data/spec/rails_app/postcss.config.js +12 -0
  189. data/spec/roles/acts_as_group_spec.rb +0 -2
  190. data/spec/roles/acts_as_notifiable_spec.rb +1 -3
  191. data/spec/roles/acts_as_notifier_spec.rb +0 -2
  192. data/spec/roles/acts_as_target_spec.rb +0 -4
  193. data/spec/spec_helper.rb +7 -15
  194. data/spec/version_spec.rb +31 -0
  195. metadata +187 -13
@@ -3,22 +3,11 @@ module ActivityNotification
3
3
  module OptionalTarget
4
4
  # Abstract optional target class to develop optional notification target class.
5
5
  class Base
6
- # View context to render notification message
7
- # @return View context to render notification message
8
- attr_accessor :view_context
9
-
10
6
  # Initialize method to create view context in this OptionalTarget instance
11
7
  # @param [Hash] options Options for initializing target
12
8
  # @option options [Boolean] :skip_initializing_target (false) Whether skip calling initialize_target method
13
9
  # @option options [Hash] others Options for initializing target
14
10
  def initialize(options = {})
15
- @view_context = ActionView::Base.new(ActionController::Base.view_paths, {})
16
- @view_context.class_eval do
17
- include Rails.application.routes.url_helpers
18
- def default_url_options
19
- ActionMailer::Base.default_url_options
20
- end
21
- end
22
11
  initialize_target(options) unless options.delete(:skip_initializing_target)
23
12
  end
24
13
 
@@ -64,12 +53,17 @@ module ActivityNotification
64
53
  "activity_notification/optional_targets/default/base"
65
54
  ]
66
55
  options[:fallback] ||= :default
67
- @view_context.assign((options[:assignment] || {}).merge(notification: notification, target: notification.target))
68
56
 
69
57
  message, missing_template = nil, nil
70
58
  partial_root_list.each do |partial_root|
71
59
  begin
72
- message = notification.render(@view_context, options.merge(partial_root: partial_root)).to_str
60
+ message = notification.render(
61
+ ActivityNotification::NotificationsController.renderer,
62
+ options.merge(
63
+ partial_root: partial_root,
64
+ assigns: (options[:assignment] || {}).merge(notification: notification, target: notification.target)
65
+ )
66
+ ).to_s
73
67
  break
74
68
  rescue ActionView::MissingTemplate => e
75
69
  missing_template = e
@@ -126,6 +126,22 @@ module ActivityNotification
126
126
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
127
127
  scope :filtered_by_group, ->(group) { where(group: group) }
128
128
 
129
+ # Selects filtered notifications later than specified time.
130
+ # @example Get filtered unopened notificatons of the @user later than @notification
131
+ # @notifications = @user.notifications.unopened_only.later_than(@notification.created_at)
132
+ # @scope class
133
+ # @param [Time] Created time of the notifications for filter
134
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
135
+ scope :later_than, ->(created_time) { where('created_at > ?', created_time) }
136
+
137
+ # Selects filtered notifications earlier than specified time.
138
+ # @example Get filtered unopened notificatons of the @user earlier than @notification
139
+ # @notifications = @user.notifications.unopened_only.earlier_than(@notification.created_at)
140
+ # @scope class
141
+ # @param [Time] Created time of the notifications for filter
142
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
143
+ scope :earlier_than, ->(created_time) { where('created_at < ?', created_time) }
144
+
129
145
  # Includes target instance with query for notifications.
130
146
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with target
131
147
  scope :with_target, -> { includes(:target) }
@@ -152,7 +168,7 @@ module ActivityNotification
152
168
 
153
169
  # Raise DeleteRestrictionError for notifications.
154
170
  # @param [String] error_text Error text for raised exception
155
- # @raise DeleteRestrictionError
171
+ # @raise [ActiveRecord::DeleteRestrictionError] DeleteRestrictionError from used ORM
156
172
  # @return [void]
157
173
  def self.raise_delete_restriction_error(error_text)
158
174
  raise ::ActiveRecord::DeleteRestrictionError.new(error_text)
@@ -17,7 +17,7 @@ module ActivityNotification
17
17
  serialize :optional_targets, Hash
18
18
 
19
19
  validates :target, presence: true
20
- validates :key, presence: true
20
+ validates :key, presence: true, uniqueness: { scope: :target }
21
21
  validates_inclusion_of :subscribing, in: [true, false]
22
22
  validates_inclusion_of :subscribing_to_email, in: [true, false]
23
23
  validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false
@@ -249,6 +249,26 @@ module Dynamoid # :nodoc: all
249
249
  where(key: key)
250
250
  end
251
251
 
252
+ # Selects filtered notifications later than specified time.
253
+ # @example Get filtered unopened notificatons of the @user later than @notification
254
+ # @notifications = @user.notifications.unopened_only.later_than(@notification.created_at)
255
+ # @scope class
256
+ # @param [Time] Created time of the notifications for filter
257
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
258
+ def later_than(created_time)
259
+ where('created_at.gt': created_time)
260
+ end
261
+
262
+ # Selects filtered notifications earlier than specified time.
263
+ # @example Get filtered unopened notificatons of the @user earlier than @notification
264
+ # @notifications = @user.notifications.unopened_only.earlier_than(@notification.created_at)
265
+ # @scope class
266
+ # @param [Time] Created time of the notifications for filter
267
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
268
+ def earlier_than(created_time)
269
+ where('created_at.lt': created_time)
270
+ end
271
+
252
272
  # Selects filtered notifications or subscriptions by notifiable_type, group or key with filter options.
253
273
  # @example Get filtered unopened notificatons of the @user for Comment notifiable class
254
274
  # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
@@ -269,6 +289,8 @@ module Dynamoid # :nodoc: all
269
289
  # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
270
290
  # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
271
291
  # @option options [String] :filtered_by_key (nil) Key of the notification for filter
292
+ # @option options [String] :later_than (nil) ISO 8601 format time to filter notification index later than specified time
293
+ # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notification index earlier than specified time
272
294
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ['created_at.gt': time.hour.ago])
273
295
  # @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
274
296
  def filtered_by_options(options = {})
@@ -286,6 +308,12 @@ module Dynamoid # :nodoc: all
286
308
  if options.has_key?(:filtered_by_key)
287
309
  filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
288
310
  end
311
+ if options.has_key?(:later_than)
312
+ filtered_notifications = filtered_notifications.later_than(Time.iso8601(options[:later_than]))
313
+ end
314
+ if options.has_key?(:earlier_than)
315
+ filtered_notifications = filtered_notifications.earlier_than(Time.iso8601(options[:earlier_than]))
316
+ end
289
317
  if options.has_key?(:custom_filter)
290
318
  filtered_notifications = filtered_notifications.where(options[:custom_filter])
291
319
  end
@@ -1,6 +1,6 @@
1
1
  require 'dynamoid/adapter_plugin/aws_sdk_v3'
2
2
 
3
- # Entend Dynamoid to support none, limit, exists?, update_all in Dynamoid::Criteria::Chain.
3
+ # Entend Dynamoid v3.1.0 to support none, limit, exists?, update_all, serializable_hash in Dynamoid::Criteria::Chain.
4
4
  # ActivityNotification project will try to contribute these fundamental functions to Dynamoid upstream.
5
5
  # @private
6
6
  module Dynamoid # :nodoc: all
@@ -32,6 +32,7 @@ module Dynamoid # :nodoc: all
32
32
  # https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria/chain.rb
33
33
  # @private
34
34
  class Chain
35
+ # Return new none object
35
36
  def none
36
37
  None.new(self.source)
37
38
  end
@@ -64,6 +65,11 @@ module Dynamoid # :nodoc: all
64
65
  document.update_attributes(conditions)
65
66
  end
66
67
  end
68
+
69
+ # Return serializable_hash as array
70
+ def serializable_hash(options = {})
71
+ all.to_a.map { |r| r.serializable_hash(options) }
72
+ end
67
73
  end
68
74
 
69
75
  # https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/criteria.rb
@@ -163,6 +169,78 @@ module Dynamoid # :nodoc: all
163
169
  end
164
170
  end
165
171
 
172
+ # Entend Dynamoid to support uniqueness validator
173
+ # @private
174
+ module Dynamoid # :nodoc: all
175
+ # https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/validations.rb
176
+ # @private
177
+ module Validations
178
+ # Validates whether or not a field is unique against the records in the database.
179
+ class UniquenessValidator < ActiveModel::EachValidator
180
+ # Validate the document for uniqueness violations.
181
+ # @param [Document] document The document to validate.
182
+ # @param [Symbol] attribute The name of the attribute.
183
+ # @param [Object] value The value of the object.
184
+ def validate_each(document, attribute, value)
185
+ return unless validation_required?(document, attribute)
186
+ document.errors.add(attribute, :taken, options.except(:scope).merge(value: value)) if not_unique?(document, attribute, value)
187
+ end
188
+
189
+ private
190
+
191
+ # Are we required to validate the document?
192
+ # @api private
193
+ def validation_required?(document, attribute)
194
+ document.new_record? ||
195
+ document.send("attribute_changed?", attribute.to_s) ||
196
+ scope_value_changed?(document)
197
+ end
198
+
199
+ # Scope reference has changed?
200
+ # @api private
201
+ def scope_value_changed?(document)
202
+ Array.wrap(options[:scope]).any? do |item|
203
+ document.send("attribute_changed?", item.to_s)
204
+ end
205
+ end
206
+
207
+ # Check whether a record is uniqueness.
208
+ # @api private
209
+ def not_unique?(document, attribute, value)
210
+ klass = document.class
211
+ while klass.superclass.respond_to?(:validators) && klass.superclass.validators.include?(self)
212
+ klass = klass.superclass
213
+ end
214
+ criteria = create_criteria(klass, document, attribute, value)
215
+ criteria.exists?
216
+ end
217
+
218
+ # Create the validation criteria.
219
+ # @api private
220
+ def create_criteria(base, document, attribute, value)
221
+ criteria = scope(base, document)
222
+ filter_criteria(criteria, document, attribute)
223
+ end
224
+
225
+ # Scope the criteria to the scope options provided.
226
+ # @api private
227
+ def scope(criteria, document)
228
+ Array.wrap(options[:scope]).each do |item|
229
+ criteria = filter_criteria(criteria, document, item)
230
+ end
231
+ criteria
232
+ end
233
+
234
+ # Filter the criteria.
235
+ # @api private
236
+ def filter_criteria(criteria, document, attribute)
237
+ value = document.read_attribute(attribute)
238
+ value.nil? ? criteria.where("#{attribute}.null" => true) : criteria.where(attribute => value)
239
+ end
240
+ end
241
+ end
242
+ end
243
+
166
244
  module ActivityNotification
167
245
  # Dynamoid extension module for ActivityNotification.
168
246
  module DynamoidExtension
@@ -116,7 +116,7 @@ module ActivityNotification
116
116
 
117
117
  # Raise ActivityNotification::DeleteRestrictionError for notifications.
118
118
  # @param [String] error_text Error text for raised exception
119
- # @raise ActivityNotification::DeleteRestrictionError
119
+ # @raise [ActivityNotification::DeleteRestrictionError] DeleteRestrictionError from used ORM
120
120
  # @return [void]
121
121
  def self.raise_delete_restriction_error(error_text)
122
122
  raise ActivityNotification::DeleteRestrictionError, error_text
@@ -31,7 +31,7 @@ module ActivityNotification
31
31
  global_secondary_index hash_key: :target_key, range_key: :created_at, projected_attributes: :all
32
32
 
33
33
  validates :target, presence: true
34
- validates :key, presence: true
34
+ validates :key, presence: true, uniqueness: { scope: :target_key }
35
35
  validates_inclusion_of :subscribing, in: [true, false]
36
36
  validates_inclusion_of :subscribing_to_email, in: [true, false]
37
37
  validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false
@@ -72,5 +72,27 @@ module ActivityNotification
72
72
  end
73
73
  end
74
74
 
75
+ # Monkey patching for Mongoid::Document as_json
76
+ module Mongoid
77
+ # Monkey patching for Mongoid::Document as_json
78
+ module Document
79
+ # Monkey patching for Mongoid::Document as_json
80
+ # @param [Hash] options Options parameter
81
+ # @return [Hash] Hash representing the model
82
+ def as_json(options = {})
83
+ json = super(options)
84
+ json["id"] = json["_id"].to_s.start_with?("{\"$oid\"=>") ? self.id.to_s : json["_id"].to_s
85
+ if options.has_key?(:include)
86
+ case options[:include]
87
+ when Symbol then json[options[:include].to_s] = self.send(options[:include]).as_json
88
+ when Array then options[:include].each {|model| json[model.to_s] = self.send(model).as_json }
89
+ when Hash then options[:include].each {|model, options| json[model.to_s] = self.send(model).as_json(options) }
90
+ end
91
+ end
92
+ json
93
+ end
94
+ end
95
+ end
96
+
75
97
  require_relative 'mongoid/notification.rb'
76
98
  require_relative 'mongoid/subscription.rb'
@@ -143,6 +143,22 @@ module ActivityNotification
143
143
  any_of({ :group_id.exists => false, :group_type.exists => false }, { group_id: nil, group_type: nil })
144
144
  }
145
145
 
146
+ # Selects filtered notifications later than specified time.
147
+ # @example Get filtered unopened notificatons of the @user later than @notification
148
+ # @notifications = @user.notifications.unopened_only.later_than(@notification.created_at)
149
+ # @scope class
150
+ # @param [Time] Created time of the notifications for filter
151
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
152
+ scope :later_than, ->(created_time) { where(:created_at.gt => created_time) }
153
+
154
+ # Selects filtered notifications earlier than specified time.
155
+ # @example Get filtered unopened notificatons of the @user earlier than @notification
156
+ # @notifications = @user.notifications.unopened_only.earlier_than(@notification.created_at)
157
+ # @scope class
158
+ # @param [Time] Created time of the notifications for filter
159
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
160
+ scope :earlier_than, ->(created_time) { where(:created_at.lt => created_time) }
161
+
146
162
  # Includes target instance with query for notifications.
147
163
  # @return [Mongoid::Criteria<Notificaion>] Database query of notifications with target
148
164
  scope :with_target, -> { }
@@ -179,7 +195,7 @@ module ActivityNotification
179
195
 
180
196
  # Raise ActivityNotification::DeleteRestrictionError for notifications.
181
197
  # @param [String] error_text Error text for raised exception
182
- # @raise ActivityNotification::DeleteRestrictionError
198
+ # @raise [ActivityNotification::DeleteRestrictionError] DeleteRestrictionError from used ORM
183
199
  # @return [void]
184
200
  def self.raise_delete_restriction_error(error_text)
185
201
  raise ActivityNotification::DeleteRestrictionError, error_text
@@ -28,7 +28,7 @@ module ActivityNotification
28
28
  field :optional_targets, type: Hash, default: {}
29
29
 
30
30
  validates :target, presence: true
31
- validates :key, presence: true
31
+ validates :key, presence: true, uniqueness: { scope: :target }
32
32
  validates_inclusion_of :subscribing, in: [true, false]
33
33
  validates_inclusion_of :subscribing_to_email, in: [true, false]
34
34
  validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false
@@ -23,7 +23,7 @@ module ActionDispatch::Routing
23
23
  # { controller:"activity_notification/notifications", action:"open_all", target_type:"users" }
24
24
  # move_user_notification GET /users/:user_id/notifications/:id/move(.:format)
25
25
  # { controller:"activity_notification/notifications", action:"move", target_type:"users" }
26
- # open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
26
+ # open_user_notification PUT /users/:user_id/notifications/:id/open(.:format)
27
27
  # { controller:"activity_notification/notifications", action:"open", target_type:"users" }
28
28
  #
29
29
  # You can also configure notification routes with scope like this:
@@ -42,7 +42,7 @@ module ActionDispatch::Routing
42
42
  # { controller:"activity_notification/notifications", action:"open_all", target_type:"users", routing_scope: :myscope }
43
43
  # move_myscope_user_notification GET /myscope/users/:user_id/notifications/:id/move(.:format)
44
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)
45
+ # open_myscope_user_notification PUT /myscope/users/:user_id/notifications/:id/open(.:format)
46
46
  # { controller:"activity_notification/notifications", action:"open", target_type:"users", routing_scope: :myscope }
47
47
  #
48
48
  # When you use devise authentication and you want make notification targets assciated with devise,
@@ -60,7 +60,7 @@ module ActionDispatch::Routing
60
60
  # { controller:"activity_notification/notifications_with_devise", action:"open_all", target_type:"users", devise_type:"users" }
61
61
  # move_user_notification GET /users/:user_id/notifications/:id/move(.:format)
62
62
  # { controller:"activity_notification/notifications_with_devise", action:"move", target_type:"users", devise_type:"users" }
63
- # open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
63
+ # open_user_notification PUT /users/:user_id/notifications/:id/open(.:format)
64
64
  # { controller:"activity_notification/notifications_with_devise", action:"open", target_type:"users", devise_type:"users" }
65
65
  #
66
66
  # When you use with_devise option and you want to make simple default routes as follows, you can use devise_default_routes option:
@@ -77,9 +77,31 @@ module ActionDispatch::Routing
77
77
  # { controller:"activity_notification/notifications_with_devise", action:"open_all", target_type:"users", devise_type:"users" }
78
78
  # move_user_notification GET /notifications/:id/move(.:format)
79
79
  # { controller:"activity_notification/notifications_with_devise", action:"move", target_type:"users", devise_type:"users" }
80
- # open_user_notification POST /notifications/:id/open(.:format)
80
+ # open_user_notification PUT /notifications/:id/open(.:format)
81
81
  # { controller:"activity_notification/notifications_with_devise", action:"open", target_type:"users", devise_type:"users" }
82
82
  #
83
+ # When you use activity_notification controllers as REST API mode,
84
+ # you can create as follows in your routes:
85
+ # scope :api do
86
+ # scope :"v2" do
87
+ # notify_to :users, api_mode: true
88
+ # end
89
+ # end
90
+ # This api_mode option creates the needed routes as REST API:
91
+ # # Notification as API mode routes
92
+ # GET /api/v2/users/:user_id/notifications(.:format)
93
+ # { controller:"activity_notification/notifications_api", action:"index", target_type:"users" }
94
+ # GET /api/v2/users/:user_id/notifications/:id(.:format)
95
+ # { controller:"activity_notification/notifications_api", action:"show", target_type:"users" }
96
+ # DELETE /api/v2/users/:user_id/notifications/:id(.:format)
97
+ # { controller:"activity_notification/notifications_api", action:"destroy", target_type:"users" }
98
+ # POST /api/v2/users/:user_id/notifications/open_all(.:format)
99
+ # { controller:"activity_notification/notifications_api", action:"open_all", target_type:"users" }
100
+ # GET /api/v2/users/:user_id/notifications/:id/move(.:format)
101
+ # { controller:"activity_notification/notifications_api", action:"move", target_type:"users" }
102
+ # PUT /api/v2/users/:user_id/notifications/:id/open(.:format)
103
+ # { controller:"activity_notification/notifications_api", action:"open", target_type:"users" }
104
+ #
83
105
  # When you would like to define subscription management paths with notification paths,
84
106
  # you can create as follows in your routes:
85
107
  # notify_to :users, with_subscription: true
@@ -102,12 +124,19 @@ module ActionDispatch::Routing
102
124
  # scope :myscope, as: :myscope do
103
125
  # notify_to :myscope, with_devise: :users, devise_default_routes: true, with_subscription: true, routing_scope: :myscope
104
126
  # end
127
+ # @example Define notification paths as API mode including subscription paths
128
+ # scope :api do
129
+ # scope :"v2" do
130
+ # notify_to :users, api_mode: true, with_subscription: true
131
+ # end
132
+ # end
105
133
  #
106
134
  # @overload notify_to(*resources, *options)
107
135
  # @param [Symbol] resources Resources to notify
108
136
  # @option options [String] :routing_scope (nil) Routing scope for notification routes
109
137
  # @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
110
138
  # @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
139
+ # @option options [Boolean] :api_mode (false) Whether you will use activity_notification controllers as REST API mode
111
140
  # @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
141
  # @option options [String] :model (:notifications) Model name of notifications
113
142
  # @option options [String] :controller ("activity_notification/notifications" | activity_notification/notifications_with_devise") :controller option as resources routing
@@ -120,7 +149,7 @@ module ActionDispatch::Routing
120
149
 
121
150
  resources.each do |target|
122
151
  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 }
152
+ resources_options = options.select { |key, _| [:api_mode, :with_devise, :devise_default_routes, :with_subscription, :subscription_option, :model, :devise_defaults].exclude? key }
124
153
  if options[:with_devise].present? && options[:devise_default_routes].present?
125
154
  create_notification_routes options, resources_options
126
155
  else
@@ -146,23 +175,25 @@ module ActionDispatch::Routing
146
175
  # # Subscription routes
147
176
  # user_subscriptions GET /users/:user_id/subscriptions(.:format)
148
177
  # { controller:"activity_notification/subscriptions", action:"index", target_type:"users" }
178
+ # find_user_subscriptions GET /users/:user_id/subscriptions/find(.:format)
179
+ # { controller:"activity_notification/subscriptions", action:"find", target_type:"users" }
149
180
  # user_subscription GET /users/:user_id/subscriptions/:id(.:format)
150
181
  # { controller:"activity_notification/subscriptions", action:"show", target_type:"users" }
151
- # open_all_user_subscriptions POST /users/:user_id/subscriptions(.:format)
182
+ # PUT /users/:user_id/subscriptions(.:format)
152
183
  # { controller:"activity_notification/subscriptions", action:"create", target_type:"users" }
153
- # user_subscription DELETE /users/:user_id/subscriptions/:id(.:format)
184
+ # DELETE /users/:user_id/subscriptions/:id(.:format)
154
185
  # { controller:"activity_notification/subscriptions", action:"destroy", target_type:"users" }
155
- # subscribe_user_subscription POST /users/:user_id/subscriptions/:id/subscribe(.:format)
186
+ # subscribe_user_subscription PUT /users/:user_id/subscriptions/:id/subscribe(.:format)
156
187
  # { controller:"activity_notification/subscriptions", action:"subscribe", target_type:"users" }
157
- # unsubscribe_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe(.:format)
188
+ # unsubscribe_user_subscription PUT /users/:user_id/subscriptions/:id/unsubscribe(.:format)
158
189
  # { controller:"activity_notification/subscriptions", action:"unsubscribe", target_type:"users" }
159
- # subscribe_to_email_user_subscription POST /users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
190
+ # subscribe_to_email_user_subscription PUT /users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
160
191
  # { controller:"activity_notification/subscriptions", action:"subscribe_to_email", target_type:"users" }
161
- # unsubscribe_to_email_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
192
+ # unsubscribe_to_email_user_subscription PUT /users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
162
193
  # { controller:"activity_notification/subscriptions", action:"unsubscribe_to_email", target_type:"users" }
163
- # subscribe_to_optional_target_user_subscription POST /users/:user_id/subscriptions/:id/subscribe_to_optional_target(.:format)
194
+ # subscribe_to_optional_target_user_subscription PUT /users/:user_id/subscriptions/:id/subscribe_to_optional_target(.:format)
164
195
  # { controller:"activity_notification/subscriptions", action:"subscribe_to_optional_target", target_type:"users" }
165
- # unsubscribe_to_optional_target_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
196
+ # unsubscribe_to_optional_target_user_subscription PUT /users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
166
197
  # { controller:"activity_notification/subscriptions", action:"unsubscribe_to_optional_target", target_type:"users" }
167
198
  #
168
199
  # You can also configure notification routes with scope like this:
@@ -173,23 +204,25 @@ module ActionDispatch::Routing
173
204
  # # Subscription routes
174
205
  # myscope_user_subscriptions GET /myscope/users/:user_id/subscriptions(.:format)
175
206
  # { controller:"activity_notification/subscriptions", action:"index", target_type:"users", routing_scope: :myscope }
207
+ # find_myscope_user_subscriptions GET /myscope/users/:user_id/subscriptions/find(.:format)
208
+ # { controller:"activity_notification/subscriptions", action:"find", target_type:"users", routing_scope: :myscope }
176
209
  # myscope_user_subscription GET /myscope/users/:user_id/subscriptions/:id(.:format)
177
210
  # { 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)
211
+ # PUT /myscope/users/:user_id/subscriptions(.:format)
179
212
  # { controller:"activity_notification/subscriptions", action:"create", target_type:"users", routing_scope: :myscope }
180
- # myscope_user_subscription DELETE /myscope/users/:user_id/subscriptions/:id(.:format)
213
+ # DELETE /myscope/users/:user_id/subscriptions/:id(.:format)
181
214
  # { 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)
215
+ # subscribe_myscope_user_subscription PUT /myscope/users/:user_id/subscriptions/:id/subscribe(.:format)
183
216
  # { 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)
217
+ # unsubscribe_myscope_user_subscription PUT /myscope/users/:user_id/subscriptions/:id/unsubscribe(.:format)
185
218
  # { 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)
219
+ # subscribe_to_email_myscope_user_subscription PUT /myscope/users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
187
220
  # { 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)
221
+ # unsubscribe_to_email_myscope_user_subscription PUT /myscope/users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
189
222
  # { 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)
223
+ # subscribe_to_optional_target_myscope_user_subscription PUT /myscope/users/:user_id/subscriptions/:id/subscribe_to_optional_target(.:format)
191
224
  # { 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)
225
+ # unsubscribe_to_optional_target_myscope_user_subscription PUT /myscope/users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
193
226
  # { controller:"activity_notification/subscriptions", action:"unsubscribe_to_optional_target", target_type:"users", routing_scope: :myscope }
194
227
  #
195
228
  # When you use devise authentication and you want make subscription targets assciated with devise,
@@ -199,23 +232,25 @@ module ActionDispatch::Routing
199
232
  # # Subscription with devise routes
200
233
  # user_subscriptions GET /users/:user_id/subscriptions(.:format)
201
234
  # { controller:"activity_notification/subscriptions_with_devise", action:"index", target_type:"users", devise_type:"users" }
235
+ # find_user_subscriptions GET /users/:user_id/subscriptions/find(.:format)
236
+ # { controller:"activity_notification/subscriptions_with_devise", action:"find", target_type:"users", devise_type:"users" }
202
237
  # user_subscription GET /users/:user_id/subscriptions/:id(.:format)
203
238
  # { controller:"activity_notification/subscriptions_with_devise", action:"show", target_type:"users", devise_type:"users" }
204
- # open_all_user_subscriptions POST /users/:user_id/subscriptions(.:format)
239
+ # PUT /users/:user_id/subscriptions(.:format)
205
240
  # { controller:"activity_notification/subscriptions_with_devise", action:"create", target_type:"users", devise_type:"users" }
206
- # user_subscription DELETE /users/:user_id/subscriptions/:id(.:format)
241
+ # DELETE /users/:user_id/subscriptions/:id(.:format)
207
242
  # { controller:"activity_notification/subscriptions_with_devise", action:"destroy", target_type:"users", devise_type:"users" }
208
- # subscribe_user_subscription POST /users/:user_id/subscriptions/:id/subscribe(.:format)
243
+ # subscribe_user_subscription PUT /users/:user_id/subscriptions/:id/subscribe(.:format)
209
244
  # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe", target_type:"users", devise_type:"users" }
210
- # unsubscribe_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe(.:format)
245
+ # unsubscribe_user_subscription PUT /users/:user_id/subscriptions/:id/unsubscribe(.:format)
211
246
  # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe", target_type:"users", devise_type:"users" }
212
- # subscribe_to_email_user_subscription POST /users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
247
+ # subscribe_to_email_user_subscription PUT /users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
213
248
  # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe_to_email", target_type:"users", devise_type:"users" }
214
- # unsubscribe_to_email_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
249
+ # unsubscribe_to_email_user_subscription PUT /users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
215
250
  # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_email", target_type:"users", devise_type:"users" }
216
- # subscribe_to_optional_target_user_subscription POST /users/:user_id/subscriptions/:id/subscribe_to_optional_target(.:format)
251
+ # subscribe_to_optional_target_user_subscription PUT /users/:user_id/subscriptions/:id/subscribe_to_optional_target(.:format)
217
252
  # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe_to_optional_target", target_type:"users", devise_type:"users" }
218
- # unsubscribe_to_optional_target_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
253
+ # unsubscribe_to_optional_target_user_subscription PUT /users/:user_id/subscriptions/:id/unsubscribe_to_optional_target(.:format)
219
254
  # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_optional_target", target_type:"users", devise_type:"users" }
220
255
  #
221
256
  # When you use with_devise option and you want to make simple default routes as follows, you can use devise_default_routes option:
@@ -224,37 +259,80 @@ module ActionDispatch::Routing
224
259
  # # Subscription with devise routes
225
260
  # user_subscriptions GET /subscriptions(.:format)
226
261
  # { controller:"activity_notification/subscriptions_with_devise", action:"index", target_type:"users", devise_type:"users" }
262
+ # find_user_subscriptions GET /subscriptions/find(.:format)
263
+ # { controller:"activity_notification/subscriptions_with_devise", action:"find", target_type:"users", devise_type:"users" }
227
264
  # user_subscription GET /subscriptions/:id(.:format)
228
265
  # { controller:"activity_notification/subscriptions_with_devise", action:"show", target_type:"users", devise_type:"users" }
229
- # open_all_user_subscriptions POST /subscriptions(.:format)
266
+ # PUT /subscriptions(.:format)
230
267
  # { controller:"activity_notification/subscriptions_with_devise", action:"create", target_type:"users", devise_type:"users" }
231
- # user_subscription DELETE /subscriptions/:id(.:format)
268
+ # DELETE /subscriptions/:id(.:format)
232
269
  # { controller:"activity_notification/subscriptions_with_devise", action:"destroy", target_type:"users", devise_type:"users" }
233
- # subscribe_user_subscription POST /subscriptions/:id/subscribe(.:format)
270
+ # subscribe_user_subscription PUT /subscriptions/:id/subscribe(.:format)
234
271
  # { controller:"activity_notification/subscriptions_with_devise", action:"subscribe", target_type:"users", devise_type:"users" }
235
- # unsubscribe_user_subscription POST /subscriptions/:id/unsubscribe(.:format)
272
+ # unsubscribe_user_subscription PUT /subscriptions/:id/unsubscribe(.:format)
236
273
  # { 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)
274
+ # subscribe_to_email_user_subscription PUT /subscriptions/:id/subscribe_to_email(.:format)
238
275
  # { 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)
276
+ # unsubscribe_to_email_user_subscription PUT /subscriptions/:id/unsubscribe_to_email(.:format)
240
277
  # { 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)
278
+ # subscribe_to_optional_target_user_subscription PUT /subscriptions/:id/subscribe_to_optional_target(.:format)
242
279
  # { 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)
280
+ # unsubscribe_to_optional_target_user_subscription PUT /subscriptions/:id/unsubscribe_to_optional_target(.:format)
244
281
  # { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_optional_target", target_type:"users", devise_type:"users" }
245
282
  #
283
+ # When you use activity_notification controllers as REST API mode,
284
+ # you can create as follows in your routes:
285
+ # scope :api do
286
+ # scope :"v2" do
287
+ # subscribed_by :users, api_mode: true
288
+ # end
289
+ # end
290
+ # This api_mode option creates the needed routes as REST API:
291
+ # # Subscription as API mode routes
292
+ # GET /subscriptions(.:format)
293
+ # { controller:"activity_notification/subscriptions_api", action:"index", target_type:"users" }
294
+ # GET /subscriptions/find(.:format)
295
+ # { controller:"activity_notification/subscriptions_api", action:"find", target_type:"users" }
296
+ # GET /subscriptions/optional_target_names(.:format)
297
+ # { controller:"activity_notification/subscriptions_api", action:"optional_target_names", target_type:"users" }
298
+ # GET /subscriptions/:id(.:format)
299
+ # { controller:"activity_notification/subscriptions_api", action:"show", target_type:"users" }
300
+ # PUT /subscriptions(.:format)
301
+ # { controller:"activity_notification/subscriptions_api", action:"create", target_type:"users" }
302
+ # DELETE /subscriptions/:id(.:format)
303
+ # { controller:"activity_notification/subscriptions_api", action:"destroy", target_type:"users" }
304
+ # PUT /subscriptions/:id/subscribe(.:format)
305
+ # { controller:"activity_notification/subscriptions_api", action:"subscribe", target_type:"users" }
306
+ # PUT /subscriptions/:id/unsubscribe(.:format)
307
+ # { controller:"activity_notification/subscriptions_api", action:"unsubscribe", target_type:"users" }
308
+ # PUT /subscriptions/:id/subscribe_to_email(.:format)
309
+ # { controller:"activity_notification/subscriptions_api", action:"subscribe_to_email", target_type:"users" }
310
+ # PUT /subscriptions/:id/unsubscribe_to_email(.:format)
311
+ # { controller:"activity_notification/subscriptions_api", action:"unsubscribe_to_email", target_type:"users" }
312
+ # PUT /subscriptions/:id/subscribe_to_optional_target(.:format)
313
+ # { controller:"activity_notification/subscriptions_api", action:"subscribe_to_optional_target", target_type:"users" }
314
+ # PUT /subscriptions/:id/unsubscribe_to_optional_target(.:format)
315
+ # { controller:"activity_notification/subscriptions_api", action:"unsubscribe_to_optional_target", target_type:"users" }
316
+ #
246
317
  # @example Define subscribed_by in config/routes.rb
247
318
  # subscribed_by :users
248
319
  # @example Define subscribed_by with options
249
320
  # subscribed_by :users, except: [:index, :show]
250
321
  # @example Integrated with Devise authentication
251
322
  # subscribed_by :users, with_devise: :users
323
+ # @example Define subscription paths as API mode
324
+ # scope :api do
325
+ # scope :"v2" do
326
+ # subscribed_by :users, api_mode: true
327
+ # end
328
+ # end
252
329
  #
253
330
  # @overload subscribed_by(*resources, *options)
254
331
  # @param [Symbol] resources Resources to notify
255
332
  # @option options [String] :routing_scope (nil) Routing scope for subscription routes
256
333
  # @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
257
334
  # @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
335
+ # @option options [Boolean] :api_mode (false) Whether you will use activity_notification controllers as REST API mode
258
336
  # @option options [String] :model (:subscriptions) Model name of subscriptions
259
337
  # @option options [String] :controller ("activity_notification/subscriptions" | activity_notification/subscriptions_with_devise") :controller option as resources routing
260
338
  # @option options [Symbol] :as (nil) :as option as resources routing
@@ -266,7 +344,7 @@ module ActionDispatch::Routing
266
344
 
267
345
  resources.each do |target|
268
346
  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 }
347
+ resources_options = options.select { |key, _| [:api_mode, :with_devise, :devise_default_routes, :model, :devise_defaults].exclude? key }
270
348
  if options[:with_devise].present? && options[:devise_default_routes].present?
271
349
  create_subscription_routes options, resources_options
272
350
  else
@@ -305,20 +383,22 @@ module ActionDispatch::Routing
305
383
  # Check resources if it includes target module
306
384
  resources_name = resource.to_s.pluralize.underscore
307
385
  options[:model] ||= resources_name.to_sym
386
+ controller_name = "activity_notification/#{resources_name}"
387
+ controller_name.concat("_api") if options[:api_mode]
308
388
  if options[:with_devise].present?
309
- options[:controller] ||= "activity_notification/#{resources_name}_with_devise"
389
+ options[:controller] ||= "#{controller_name}_with_devise"
310
390
  options[:as] ||= resources_name
311
391
  # Check devise configuration in model
312
392
  options[:devise_defaults] = { devise_type: options[:with_devise].to_s }
313
393
  options[:devise_defaults] = options[:devise_defaults].merge(options.slice(:devise_default_routes))
314
394
  else
315
- options[:controller] ||= "activity_notification/#{resources_name}"
395
+ options[:controller] ||= controller_name
316
396
  options[:devise_defaults] = {}
317
397
  end
318
398
  (options[:except] ||= []).concat(except_actions)
319
399
  if options[:with_subscription].present?
320
400
  options[:subscription_option] = (options[:with_subscription].is_a?(Hash) ? options[:with_subscription] : {})
321
- .merge(options.slice(:with_devise, :devise_default_routes, :routing_scope))
401
+ .merge(options.slice(:api_mode, :with_devise, :devise_default_routes, :routing_scope))
322
402
  end
323
403
  # Support other options like :as, :path_prefix, :path_names ...
324
404
  options
@@ -337,7 +417,7 @@ module ActionDispatch::Routing
337
417
  end
338
418
  member do
339
419
  get :move unless ignore_path?(:move, options)
340
- post :open unless ignore_path?(:open, options)
420
+ put :open unless ignore_path?(:open, options)
341
421
  end
342
422
  end
343
423
  end
@@ -350,13 +430,17 @@ module ActionDispatch::Routing
350
430
  # @param [Hash] resources_options Options to send resources method
351
431
  def create_subscription_routes(options = {}, resources_options = [])
352
432
  self.resources options[:model], resources_options do
433
+ collection do
434
+ get :find unless ignore_path?(:find, options)
435
+ get :optional_target_names if options[:api_mode] && !ignore_path?(:optional_target_names, options)
436
+ end
353
437
  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)
438
+ put :subscribe unless ignore_path?(:subscribe, options)
439
+ put :unsubscribe unless ignore_path?(:unsubscribe, options)
440
+ put :subscribe_to_email unless ignore_path?(:subscribe_to_email, options)
441
+ put :unsubscribe_to_email unless ignore_path?(:unsubscribe_to_email, options)
442
+ put :subscribe_to_optional_target unless ignore_path?(:subscribe_to_optional_target, options)
443
+ put :unsubscribe_to_optional_target unless ignore_path?(:unsubscribe_to_optional_target, options)
360
444
  end
361
445
  end
362
446
  end