activity_notification 2.0.0 → 2.1.0

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