activity_notification 1.4.4 → 2.2.4

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 (271) hide show
  1. checksums.yaml +5 -5
  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/.github/workflows/build.yml +116 -0
  6. data/.gitignore +15 -3
  7. data/CHANGELOG.md +200 -1
  8. data/Gemfile +17 -2
  9. data/Procfile +2 -0
  10. data/README.md +168 -1033
  11. data/Rakefile +19 -10
  12. data/activity_notification.gemspec +14 -9
  13. data/app/channels/activity_notification/notification_api_channel.rb +12 -0
  14. data/app/channels/activity_notification/notification_api_with_devise_channel.rb +46 -0
  15. data/app/channels/activity_notification/notification_channel.rb +37 -0
  16. data/app/channels/activity_notification/notification_with_devise_channel.rb +51 -0
  17. data/app/controllers/activity_notification/apidocs_controller.rb +75 -0
  18. data/app/controllers/activity_notification/notifications_api_controller.rb +143 -0
  19. data/app/controllers/activity_notification/notifications_api_with_devise_controller.rb +7 -0
  20. data/app/controllers/activity_notification/notifications_controller.rb +60 -54
  21. data/app/controllers/activity_notification/subscriptions_api_controller.rb +197 -0
  22. data/app/controllers/activity_notification/subscriptions_api_with_devise_controller.rb +7 -0
  23. data/app/controllers/activity_notification/subscriptions_controller.rb +83 -73
  24. data/app/jobs/activity_notification/notify_all_job.rb +25 -0
  25. data/app/jobs/activity_notification/notify_job.rb +26 -0
  26. data/app/jobs/activity_notification/notify_to_job.rb +25 -0
  27. data/app/views/activity_notification/notifications/default/_default.html.erb +23 -23
  28. data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +19 -19
  29. data/app/views/activity_notification/notifications/default/_index.html.erb +3 -3
  30. data/app/views/activity_notification/notifications/default/index.html.erb +60 -7
  31. data/app/views/activity_notification/notifications/default/open.js.erb +2 -2
  32. data/app/views/activity_notification/notifications/default/open_all.js.erb +2 -2
  33. data/app/views/activity_notification/notifications/default/show.html.erb +2 -2
  34. data/app/views/activity_notification/optional_targets/default/action_cable_channel/_default.html.erb +176 -0
  35. data/app/views/activity_notification/optional_targets/default/base/_default.text.erb +1 -1
  36. data/app/views/activity_notification/optional_targets/default/slack/_default.text.erb +1 -1
  37. data/app/views/activity_notification/subscriptions/default/_form.html.erb +2 -2
  38. data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +5 -33
  39. data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +8 -8
  40. data/app/views/activity_notification/subscriptions/default/index.html.erb +13 -9
  41. data/app/views/activity_notification/subscriptions/default/show.html.erb +3 -3
  42. data/app/views/activity_notification/subscriptions/default/subscribe.js.erb +1 -1
  43. data/app/views/activity_notification/subscriptions/default/subscribe_to_email.js.erb +1 -1
  44. data/app/views/activity_notification/subscriptions/default/subscribe_to_optional_target.js.erb +1 -1
  45. data/app/views/activity_notification/subscriptions/default/unsubscribe.js.erb +1 -1
  46. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_email.js.erb +1 -1
  47. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_optional_target.js.erb +1 -1
  48. data/bin/_dynamodblocal +4 -0
  49. data/bin/bundle_update.sh +7 -0
  50. data/bin/deploy_on_heroku.sh +16 -0
  51. data/bin/install_dynamodblocal.sh +5 -0
  52. data/bin/start_dynamodblocal.sh +47 -0
  53. data/bin/stop_dynamodblocal.sh +34 -0
  54. data/docs/CODE_OF_CONDUCT.md +76 -0
  55. data/docs/CONTRIBUTING.md +36 -0
  56. data/docs/Functions.md +1146 -0
  57. data/docs/Setup.md +817 -0
  58. data/docs/Testing.md +148 -0
  59. data/gemfiles/Gemfile.rails-5.0 +8 -1
  60. data/gemfiles/Gemfile.rails-5.1 +7 -1
  61. data/gemfiles/Gemfile.rails-5.2 +24 -0
  62. data/gemfiles/Gemfile.rails-6.0 +23 -0
  63. data/gemfiles/Gemfile.rails-6.1 +22 -0
  64. data/gemfiles/Gemfile.rails-7.0 +25 -0
  65. data/lib/activity_notification/apis/notification_api.rb +356 -159
  66. data/lib/activity_notification/apis/subscription_api.rb +98 -59
  67. data/lib/activity_notification/apis/swagger.rb +6 -0
  68. data/lib/activity_notification/common.rb +18 -7
  69. data/lib/activity_notification/config.rb +176 -30
  70. data/lib/activity_notification/controllers/common_api_controller.rb +30 -0
  71. data/lib/activity_notification/controllers/common_controller.rb +47 -27
  72. data/lib/activity_notification/controllers/concerns/swagger/error_responses.rb +55 -0
  73. data/lib/activity_notification/controllers/concerns/swagger/notifications_api.rb +273 -0
  74. data/lib/activity_notification/controllers/concerns/swagger/notifications_parameters.rb +92 -0
  75. data/lib/activity_notification/controllers/concerns/swagger/subscriptions_api.rb +405 -0
  76. data/lib/activity_notification/controllers/concerns/swagger/subscriptions_parameters.rb +50 -0
  77. data/lib/activity_notification/controllers/devise_authentication_controller.rb +22 -5
  78. data/lib/activity_notification/gem_version.rb +14 -0
  79. data/lib/activity_notification/helpers/errors.rb +6 -0
  80. data/lib/activity_notification/helpers/view_helpers.rb +118 -28
  81. data/lib/activity_notification/mailers/helpers.rb +19 -12
  82. data/lib/activity_notification/models/concerns/notifiable.rb +142 -55
  83. data/lib/activity_notification/models/concerns/subscriber.rb +28 -13
  84. data/lib/activity_notification/models/concerns/swagger/error_schema.rb +36 -0
  85. data/lib/activity_notification/models/concerns/swagger/notification_schema.rb +209 -0
  86. data/lib/activity_notification/models/concerns/swagger/subscription_schema.rb +162 -0
  87. data/lib/activity_notification/models/concerns/target.rb +131 -32
  88. data/lib/activity_notification/models/notification.rb +1 -0
  89. data/lib/activity_notification/models/subscription.rb +1 -0
  90. data/lib/activity_notification/models.rb +23 -1
  91. data/lib/activity_notification/optional_targets/action_cable_api_channel.rb +69 -0
  92. data/lib/activity_notification/optional_targets/action_cable_channel.rb +68 -0
  93. data/lib/activity_notification/optional_targets/base.rb +9 -15
  94. data/lib/activity_notification/orm/active_record/notification.rb +23 -34
  95. data/lib/activity_notification/orm/active_record/subscription.rb +1 -1
  96. data/lib/activity_notification/orm/active_record.rb +1 -1
  97. data/lib/activity_notification/orm/dynamoid/extension.rb +262 -0
  98. data/lib/activity_notification/orm/dynamoid/notification.rb +224 -0
  99. data/lib/activity_notification/orm/dynamoid/subscription.rb +82 -0
  100. data/lib/activity_notification/orm/dynamoid.rb +530 -0
  101. data/lib/activity_notification/orm/mongoid/notification.rb +29 -28
  102. data/lib/activity_notification/orm/mongoid/subscription.rb +3 -3
  103. data/lib/activity_notification/orm/mongoid.rb +33 -1
  104. data/lib/activity_notification/rails/routes.rb +273 -60
  105. data/lib/activity_notification/renderable.rb +22 -7
  106. data/lib/activity_notification/roles/acts_as_notifiable.rb +64 -1
  107. data/lib/activity_notification/roles/acts_as_target.rb +99 -9
  108. data/lib/activity_notification/version.rb +1 -1
  109. data/lib/activity_notification.rb +14 -0
  110. data/lib/generators/activity_notification/controllers_generator.rb +2 -1
  111. data/lib/generators/templates/activity_notification.rb +61 -7
  112. data/lib/generators/templates/controllers/README +2 -2
  113. data/lib/generators/templates/controllers/notifications_api_controller.rb +31 -0
  114. data/lib/generators/templates/controllers/notifications_api_with_devise_controller.rb +31 -0
  115. data/lib/generators/templates/controllers/notifications_controller.rb +1 -37
  116. data/lib/generators/templates/controllers/notifications_with_devise_controller.rb +1 -45
  117. data/lib/generators/templates/controllers/subscriptions_api_controller.rb +61 -0
  118. data/lib/generators/templates/controllers/subscriptions_api_with_devise_controller.rb +61 -0
  119. data/lib/generators/templates/controllers/subscriptions_controller.rb +14 -37
  120. data/lib/generators/templates/controllers/subscriptions_with_devise_controller.rb +14 -45
  121. data/lib/generators/templates/migrations/migration.rb +5 -5
  122. data/lib/generators/templates/models/README +8 -4
  123. data/lib/generators/templates/models/notification.rb +1 -1
  124. data/lib/generators/templates/models/subscription.rb +1 -1
  125. data/lib/tasks/activity_notification_tasks.rake +14 -4
  126. data/package.json +8 -0
  127. data/spec/channels/notification_api_channel_shared_examples.rb +59 -0
  128. data/spec/channels/notification_api_channel_spec.rb +49 -0
  129. data/spec/channels/notification_api_with_devise_channel_spec.rb +76 -0
  130. data/spec/channels/notification_channel_shared_examples.rb +59 -0
  131. data/spec/channels/notification_channel_spec.rb +48 -0
  132. data/spec/channels/notification_with_devise_channel_spec.rb +97 -0
  133. data/spec/concerns/apis/notification_api_spec.rb +177 -12
  134. data/spec/concerns/apis/subscription_api_spec.rb +146 -4
  135. data/spec/concerns/common_spec.rb +25 -3
  136. data/spec/concerns/models/notifiable_spec.rb +161 -11
  137. data/spec/concerns/models/subscriber_spec.rb +253 -79
  138. data/spec/concerns/models/target_spec.rb +180 -47
  139. data/spec/concerns/renderable_spec.rb +35 -16
  140. data/spec/config_spec.rb +52 -1
  141. data/spec/controllers/controller_spec_utility.rb +100 -0
  142. data/spec/controllers/notifications_api_controller_shared_examples.rb +506 -0
  143. data/spec/controllers/notifications_api_controller_spec.rb +19 -0
  144. data/spec/controllers/notifications_api_with_devise_controller_spec.rb +60 -0
  145. data/spec/controllers/notifications_controller_shared_examples.rb +55 -76
  146. data/spec/controllers/notifications_controller_spec.rb +1 -2
  147. data/spec/controllers/notifications_with_devise_controller_spec.rb +14 -8
  148. data/spec/controllers/subscriptions_api_controller_shared_examples.rb +750 -0
  149. data/spec/controllers/subscriptions_api_controller_spec.rb +19 -0
  150. data/spec/controllers/subscriptions_api_with_devise_controller_spec.rb +60 -0
  151. data/spec/controllers/subscriptions_controller_shared_examples.rb +99 -121
  152. data/spec/controllers/subscriptions_controller_spec.rb +1 -2
  153. data/spec/controllers/subscriptions_with_devise_controller_spec.rb +14 -8
  154. data/spec/factories/notifications.rb +1 -1
  155. data/spec/factories/subscriptions.rb +3 -3
  156. data/spec/factories/users.rb +3 -3
  157. data/spec/generators/migration/migration_generator_spec.rb +29 -4
  158. data/spec/helpers/view_helpers_spec.rb +31 -21
  159. data/spec/jobs/notify_all_job_spec.rb +23 -0
  160. data/spec/jobs/notify_job_spec.rb +23 -0
  161. data/spec/jobs/notify_to_job_spec.rb +23 -0
  162. data/spec/mailers/mailer_spec.rb +42 -1
  163. data/spec/models/dummy/dummy_group_spec.rb +4 -0
  164. data/spec/models/dummy/dummy_notifiable_spec.rb +4 -0
  165. data/spec/models/dummy/dummy_notifier_spec.rb +4 -0
  166. data/spec/models/dummy/dummy_subscriber_spec.rb +3 -0
  167. data/spec/models/dummy/dummy_target_spec.rb +4 -0
  168. data/spec/models/notification_spec.rb +181 -45
  169. data/spec/models/subscription_spec.rb +77 -27
  170. data/spec/optional_targets/action_cable_api_channel_spec.rb +34 -0
  171. data/spec/optional_targets/action_cable_channel_spec.rb +41 -0
  172. data/spec/optional_targets/amazon_sns_spec.rb +0 -2
  173. data/spec/optional_targets/slack_spec.rb +0 -2
  174. data/spec/orm/dynamoid_spec.rb +115 -0
  175. data/spec/rails_app/Rakefile +9 -0
  176. data/spec/rails_app/app/assets/config/manifest.js +3 -0
  177. data/spec/rails_app/app/assets/javascripts/application.js +2 -1
  178. data/spec/rails_app/app/assets/javascripts/cable.js +12 -0
  179. data/spec/rails_app/app/controllers/admins_controller.rb +21 -0
  180. data/spec/rails_app/app/controllers/application_controller.rb +1 -1
  181. data/spec/rails_app/app/controllers/articles_controller.rb +6 -1
  182. data/spec/rails_app/app/controllers/comments_controller.rb +3 -1
  183. data/spec/rails_app/app/controllers/spa_controller.rb +7 -0
  184. data/spec/rails_app/app/controllers/users/notifications_controller.rb +0 -65
  185. data/spec/rails_app/app/controllers/users/notifications_with_devise_controller.rb +0 -73
  186. data/spec/rails_app/app/controllers/users/subscriptions_controller.rb +0 -77
  187. data/spec/rails_app/app/controllers/users/subscriptions_with_devise_controller.rb +0 -85
  188. data/spec/rails_app/app/controllers/users_controller.rb +26 -0
  189. data/spec/rails_app/app/javascript/App.vue +40 -0
  190. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +82 -0
  191. data/spec/rails_app/app/javascript/components/Top.vue +98 -0
  192. data/spec/rails_app/app/javascript/components/notifications/Index.vue +200 -0
  193. data/spec/rails_app/app/javascript/components/notifications/Notification.vue +133 -0
  194. data/spec/rails_app/app/javascript/components/notifications/NotificationContent.vue +122 -0
  195. data/spec/rails_app/app/javascript/components/subscriptions/Index.vue +279 -0
  196. data/spec/rails_app/app/javascript/components/subscriptions/NewSubscription.vue +112 -0
  197. data/spec/rails_app/app/javascript/components/subscriptions/NotificationKey.vue +141 -0
  198. data/spec/rails_app/app/javascript/components/subscriptions/Subscription.vue +226 -0
  199. data/spec/rails_app/app/javascript/config/development.js +5 -0
  200. data/spec/rails_app/app/javascript/config/environment.js +7 -0
  201. data/spec/rails_app/app/javascript/config/production.js +5 -0
  202. data/spec/rails_app/app/javascript/config/test.js +5 -0
  203. data/spec/rails_app/app/javascript/packs/application.js +18 -0
  204. data/spec/rails_app/app/javascript/packs/spa.js +14 -0
  205. data/spec/rails_app/app/javascript/router/index.js +73 -0
  206. data/spec/rails_app/app/javascript/store/index.js +37 -0
  207. data/spec/rails_app/app/models/admin.rb +15 -10
  208. data/spec/rails_app/app/models/article.rb +25 -20
  209. data/spec/rails_app/app/models/comment.rb +27 -62
  210. data/spec/rails_app/app/models/dummy/dummy_base.rb +1 -0
  211. data/spec/rails_app/app/models/dummy/dummy_group.rb +9 -0
  212. data/spec/rails_app/app/models/dummy/dummy_notifiable.rb +1 -0
  213. data/spec/rails_app/app/models/dummy/dummy_notifiable_target.rb +27 -0
  214. data/spec/rails_app/app/models/dummy/dummy_notifier.rb +1 -0
  215. data/spec/rails_app/app/models/dummy/dummy_subscriber.rb +1 -0
  216. data/spec/rails_app/app/models/dummy/dummy_target.rb +1 -0
  217. data/spec/rails_app/app/models/user.rb +44 -18
  218. data/spec/rails_app/app/views/activity_notification/notifications/default/article/_update.html.erb +146 -0
  219. data/spec/rails_app/app/views/activity_notification/notifications/users/overridden/custom/_test.html.erb +1 -0
  220. data/spec/rails_app/app/views/activity_notification/optional_targets/admins/amazon_sns/comment/_default.text.erb +1 -1
  221. data/spec/rails_app/app/views/articles/index.html.erb +68 -20
  222. data/spec/rails_app/app/views/articles/show.html.erb +1 -1
  223. data/spec/rails_app/app/views/layouts/_header.html.erb +9 -3
  224. data/spec/rails_app/app/views/spa/index.html.erb +2 -0
  225. data/spec/rails_app/babel.config.js +72 -0
  226. data/spec/rails_app/bin/webpack +18 -0
  227. data/spec/rails_app/bin/webpack-dev-server +18 -0
  228. data/spec/rails_app/config/application.rb +26 -6
  229. data/spec/rails_app/config/cable.yml +8 -0
  230. data/spec/rails_app/config/database.yml +1 -1
  231. data/spec/rails_app/config/dynamoid.rb +13 -0
  232. data/spec/rails_app/config/environment.rb +5 -1
  233. data/spec/rails_app/config/environments/development.rb +5 -0
  234. data/spec/rails_app/config/environments/production.rb +7 -1
  235. data/spec/rails_app/config/environments/test.rb +7 -11
  236. data/spec/rails_app/config/initializers/activity_notification.rb +63 -9
  237. data/spec/rails_app/config/initializers/copy_it.aws.rb.template +6 -0
  238. data/spec/rails_app/config/initializers/devise_token_auth.rb +55 -0
  239. data/spec/rails_app/config/initializers/mysql.rb +9 -0
  240. data/spec/rails_app/config/locales/activity_notification.en.yml +10 -4
  241. data/spec/rails_app/config/routes.rb +42 -1
  242. data/spec/rails_app/config/webpack/development.js +5 -0
  243. data/spec/rails_app/config/webpack/environment.js +7 -0
  244. data/spec/rails_app/config/webpack/loaders/vue.js +6 -0
  245. data/spec/rails_app/config/webpack/production.js +5 -0
  246. data/spec/rails_app/config/webpack/test.js +5 -0
  247. data/spec/rails_app/config/webpacker.yml +97 -0
  248. data/spec/rails_app/db/migrate/{20160715050433_create_test_tables.rb → 20160716000000_create_test_tables.rb} +1 -1
  249. data/spec/rails_app/db/migrate/{20160715050420_create_activity_notification_tables.rb → 20181209000000_create_activity_notification_tables.rb} +3 -3
  250. data/spec/rails_app/db/migrate/20191201000000_add_tokens_to_users.rb +10 -0
  251. data/spec/rails_app/db/schema.rb +46 -43
  252. data/spec/rails_app/db/seeds.rb +28 -4
  253. data/spec/rails_app/lib/custom_optional_targets/raise_error.rb +14 -0
  254. data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +14 -4
  255. data/spec/rails_app/package.json +23 -0
  256. data/spec/rails_app/postcss.config.js +12 -0
  257. data/spec/roles/acts_as_group_spec.rb +0 -2
  258. data/spec/roles/acts_as_notifiable_spec.rb +80 -20
  259. data/spec/roles/acts_as_notifier_spec.rb +0 -2
  260. data/spec/roles/acts_as_target_spec.rb +1 -5
  261. data/spec/spec_helper.rb +13 -11
  262. data/spec/version_spec.rb +31 -0
  263. metadata +306 -53
  264. data/.travis.yml +0 -85
  265. data/Gemfile.lock +0 -234
  266. data/gemfiles/Gemfile.rails-4.2 +0 -17
  267. data/gemfiles/Gemfile.rails-4.2.lock +0 -225
  268. data/gemfiles/Gemfile.rails-5.0.lock +0 -234
  269. data/gemfiles/Gemfile.rails-5.1.lock +0 -234
  270. data/spec/rails_app/app/views/activity_notification/notifications/users/overriden/custom/_test.html.erb +0 -1
  271. /data/spec/rails_app/app/{models → assets/images}/.keep +0 -0
@@ -10,130 +10,189 @@ module ActivityNotification
10
10
  # Defines mailer class to send notification
11
11
  set_notification_mailer
12
12
 
13
- # Selects all notification index.
14
- # ActivityNotification::Notification.all_index!
15
- # is defined same as
16
- # ActivityNotification::Notification.group_owners_only.latest_order
17
- # @scope class
18
- # @example Get all notification index of the @user
19
- # @notifications = @user.notifications.all_index!
20
- # @notifications = @user.notifications.group_owners_only.latest_order
21
- # @param [Boolean] reverse If notification index will be ordered as earliest first
22
- # @param [Boolean] with_group_members If notification index will include group members
23
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
24
- scope :all_index!, ->(reverse = false, with_group_members = false) {
25
- target_index = with_group_members ? self : group_owners_only
26
- reverse ? target_index.earliest_order : target_index.latest_order
27
- }
28
-
29
- # Selects unopened notification index.
30
- # ActivityNotification::Notification.unopened_index
31
- # is defined same as
32
- # ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
33
- # @scope class
34
- # @example Get unopened notificaton index of the @user
35
- # @notifications = @user.notifications.unopened_index
36
- # @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
37
- # @param [Boolean] reverse If notification index will be ordered as earliest first
38
- # @param [Boolean] with_group_members If notification index will include group members
39
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
40
- scope :unopened_index, ->(reverse = false, with_group_members = false) {
41
- target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
42
- reverse ? target_index.earliest_order : target_index.latest_order
43
- }
44
-
45
- # Selects unopened notification index.
46
- # ActivityNotification::Notification.opened_index(limit)
47
- # is defined same as
48
- # ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
49
- # @scope class
50
- # @example Get unopened notificaton index of the @user with limit 10
51
- # @notifications = @user.notifications.opened_index(10)
52
- # @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
53
- # @param [Integer] limit Limit to query for opened notifications
54
- # @param [Boolean] reverse If notification index will be ordered as earliest first
55
- # @param [Boolean] with_group_members If notification index will include group members
56
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
57
- scope :opened_index, ->(limit, reverse = false, with_group_members = false) {
58
- target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
59
- reverse ? target_index.earliest_order : target_index.latest_order
60
- }
61
-
62
- # Selects filtered notifications by target_type.
63
- # @example Get filtered unopened notificatons of User as target type
64
- # @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
65
- # @scope class
66
- # @param [String] target_type Target type for filter
67
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
68
- scope :filtered_by_target_type, ->(target_type) { where(target_type: target_type) }
69
-
70
- # Selects filtered notifications by notifiable_type.
71
- # @example Get filtered unopened notificatons of the @user for Comment notifiable class
72
- # @notifications = @user.notifications.unopened_only.filtered_by_type('Comment')
73
- # @scope class
74
- # @param [String] notifiable_type Notifiable type for filter
75
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
76
- scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
77
-
78
- # Selects filtered notifications by key.
79
- # @example Get filtered unopened notificatons of the @user with key 'comment.reply'
80
- # @notifications = @user.notifications.unopened_only.filtered_by_key('comment.reply')
81
- # @scope class
82
- # @param [String] key Key of the notification for filter
83
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
84
- scope :filtered_by_key, ->(key) { where(key: key) }
85
-
86
- # Selects filtered notifications by notifiable_type, group or key with filter options.
87
- # @example Get filtered unopened notificatons of the @user for Comment notifiable class
88
- # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
89
- # @example Get filtered unopened notificatons of the @user for @article as group
90
- # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group: @article })
91
- # @example Get filtered unopened notificatons of the @user for Article instance id=1 as group
92
- # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group_type: 'Article', filtered_by_group_id: '1' })
93
- # @example Get filtered unopened notificatons of the @user with key 'comment.reply'
94
- # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
95
- # @example Get filtered unopened notificatons of the @user for Comment notifiable class with key 'comment.reply'
96
- # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
97
- # @example Get custom filtered notificatons of the @user
98
- # @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
99
- # @scope class
100
- # @param [Hash] options Options for filter
101
- # @option options [String] :filtered_by_type (nil) Notifiable type for filter
102
- # @option options [Object] :filtered_by_group (nil) Group instance for filter
103
- # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
104
- # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
105
- # @option options [String] :filtered_by_key (nil) Key of the notification for filter
106
- # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
107
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
108
- scope :filtered_by_options, ->(options = {}) {
109
- options = ActivityNotification.cast_to_indifferent_hash(options)
110
- filtered_notifications = all
111
- if options.has_key?(:filtered_by_type)
112
- filtered_notifications = filtered_notifications.filtered_by_type(options[:filtered_by_type])
113
- end
114
- if options.has_key?(:filtered_by_group)
115
- filtered_notifications = filtered_notifications.filtered_by_group(options[:filtered_by_group])
116
- end
117
- if options.has_key?(:filtered_by_group_type) && options.has_key?(:filtered_by_group_id)
118
- filtered_notifications = filtered_notifications
119
- .where(group_type: options[:filtered_by_group_type], group_id: options[:filtered_by_group_id])
13
+ # :nocov:
14
+ unless ActivityNotification.config.orm == :dynamoid
15
+ # Selects all notification index.
16
+ # ActivityNotification::Notification.all_index!
17
+ # is defined same as
18
+ # ActivityNotification::Notification.group_owners_only.latest_order
19
+ # @scope class
20
+ # @example Get all notification index of the @user
21
+ # @notifications = @user.notifications.all_index!
22
+ # @notifications = @user.notifications.group_owners_only.latest_order
23
+ # @param [Boolean] reverse If notification index will be ordered as earliest first
24
+ # @param [Boolean] with_group_members If notification index will include group members
25
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
26
+ scope :all_index!, ->(reverse = false, with_group_members = false) {
27
+ target_index = with_group_members ? self : group_owners_only
28
+ reverse ? target_index.earliest_order : target_index.latest_order
29
+ }
30
+
31
+ # Selects unopened notification index.
32
+ # ActivityNotification::Notification.unopened_index
33
+ # is defined same as
34
+ # ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
35
+ # @scope class
36
+ # @example Get unopened notificaton index of the @user
37
+ # @notifications = @user.notifications.unopened_index
38
+ # @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
39
+ # @param [Boolean] reverse If notification index will be ordered as earliest first
40
+ # @param [Boolean] with_group_members If notification index will include group members
41
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
42
+ scope :unopened_index, ->(reverse = false, with_group_members = false) {
43
+ target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
44
+ reverse ? target_index.earliest_order : target_index.latest_order
45
+ }
46
+
47
+ # Selects unopened notification index.
48
+ # ActivityNotification::Notification.opened_index(limit)
49
+ # is defined same as
50
+ # ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
51
+ # @scope class
52
+ # @example Get unopened notificaton index of the @user with limit 10
53
+ # @notifications = @user.notifications.opened_index(10)
54
+ # @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
55
+ # @param [Integer] limit Limit to query for opened notifications
56
+ # @param [Boolean] reverse If notification index will be ordered as earliest first
57
+ # @param [Boolean] with_group_members If notification index will include group members
58
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
59
+ scope :opened_index, ->(limit, reverse = false, with_group_members = false) {
60
+ target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
61
+ reverse ? target_index.earliest_order : target_index.latest_order
62
+ }
63
+
64
+ # Selects filtered notifications by target_type.
65
+ # @example Get filtered unopened notificatons of User as target type
66
+ # @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
67
+ # @scope class
68
+ # @param [String] target_type Target type for filter
69
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
70
+ scope :filtered_by_target_type, ->(target_type) { where(target_type: target_type) }
71
+
72
+ # Selects filtered notifications by notifiable_type.
73
+ # @example Get filtered unopened notificatons of the @user for Comment notifiable class
74
+ # @notifications = @user.notifications.unopened_only.filtered_by_type('Comment')
75
+ # @scope class
76
+ # @param [String] notifiable_type Notifiable type for filter
77
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
78
+ scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
79
+
80
+ # Selects filtered notifications by key.
81
+ # @example Get filtered unopened notificatons of the @user with key 'comment.reply'
82
+ # @notifications = @user.notifications.unopened_only.filtered_by_key('comment.reply')
83
+ # @scope class
84
+ # @param [String] key Key of the notification for filter
85
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
86
+ scope :filtered_by_key, ->(key) { where(key: key) }
87
+
88
+ # Selects filtered notifications by notifiable_type, group or key with filter options.
89
+ # @example Get filtered unopened notificatons of the @user for Comment notifiable class
90
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
91
+ # @example Get filtered unopened notificatons of the @user for @article as group
92
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group: @article })
93
+ # @example Get filtered unopened notificatons of the @user for Article instance id=1 as group
94
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group_type: 'Article', filtered_by_group_id: '1' })
95
+ # @example Get filtered unopened notificatons of the @user with key 'comment.reply'
96
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
97
+ # @example Get filtered unopened notificatons of the @user for Comment notifiable class with key 'comment.reply'
98
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
99
+ # @example Get custom filtered notificatons of the @user
100
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
101
+ # @scope class
102
+ # @param [Hash] options Options for filter
103
+ # @option options [String] :filtered_by_type (nil) Notifiable type for filter
104
+ # @option options [Object] :filtered_by_group (nil) Group instance for filter
105
+ # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
106
+ # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
107
+ # @option options [String] :filtered_by_key (nil) Key of the notification for filter
108
+ # @option options [String] :later_than (nil) ISO 8601 format time to filter notification index later than specified time
109
+ # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notification index earlier than specified time
110
+ # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago] with ActiveRecord or {:created_at.gt => time.hour.ago} with Mongoid)
111
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
112
+ scope :filtered_by_options, ->(options = {}) {
113
+ options = ActivityNotification.cast_to_indifferent_hash(options)
114
+ filtered_notifications = all
115
+ if options.has_key?(:filtered_by_type)
116
+ filtered_notifications = filtered_notifications.filtered_by_type(options[:filtered_by_type])
117
+ end
118
+ if options.has_key?(:filtered_by_group)
119
+ filtered_notifications = filtered_notifications.filtered_by_group(options[:filtered_by_group])
120
+ end
121
+ if options.has_key?(:filtered_by_group_type) && options.has_key?(:filtered_by_group_id)
122
+ filtered_notifications = filtered_notifications
123
+ .where(group_type: options[:filtered_by_group_type], group_id: options[:filtered_by_group_id])
124
+ end
125
+ if options.has_key?(:filtered_by_key)
126
+ filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
127
+ end
128
+ if options.has_key?(:later_than)
129
+ filtered_notifications = filtered_notifications.later_than(Time.iso8601(options[:later_than]))
130
+ end
131
+ if options.has_key?(:earlier_than)
132
+ filtered_notifications = filtered_notifications.earlier_than(Time.iso8601(options[:earlier_than]))
133
+ end
134
+ if options.has_key?(:custom_filter)
135
+ filtered_notifications = filtered_notifications.where(options[:custom_filter])
136
+ end
137
+ filtered_notifications
138
+ }
139
+
140
+ # Orders by latest (newest) first as created_at: :desc.
141
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by latest first
142
+ scope :latest_order, -> { order(created_at: :desc) }
143
+
144
+ # Orders by earliest (older) first as created_at: :asc.
145
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
146
+ scope :earliest_order, -> { order(created_at: :asc) }
147
+
148
+ # Orders by latest (newest) first as created_at: :desc.
149
+ # This method is to be overridden in implementation for each ORM.
150
+ # @param [Boolean] reverse If notifications will be ordered as earliest first
151
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of ordered notifications
152
+ scope :latest_order!, ->(reverse = false) { reverse ? earliest_order : latest_order }
153
+
154
+ # Orders by earliest (older) first as created_at: :asc.
155
+ # This method is to be overridden in implementation for each ORM.
156
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
157
+ scope :earliest_order!, -> { earliest_order }
158
+
159
+ # Returns latest notification instance.
160
+ # @return [Notification] Latest notification instance
161
+ def self.latest
162
+ latest_order.first
120
163
  end
121
- if options.has_key?(:filtered_by_key)
122
- filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
164
+
165
+ # Returns earliest notification instance.
166
+ # @return [Notification] Earliest notification instance
167
+ def self.earliest
168
+ earliest_order.first
123
169
  end
124
- if options.has_key?(:custom_filter)
125
- filtered_notifications = filtered_notifications.where(options[:custom_filter])
170
+
171
+ # Returns latest notification instance.
172
+ # This method is to be overridden in implementation for each ORM.
173
+ # @return [Notification] Latest notification instance
174
+ def self.latest!
175
+ latest
126
176
  end
127
- filtered_notifications
128
- }
129
177
 
130
- # Orders by latest (newest) first as created_at: :desc.
131
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by latest first
132
- scope :latest_order, -> { order(created_at: :desc) }
178
+ # Returns earliest notification instance.
179
+ # This method is to be overridden in implementation for each ORM.
180
+ # @return [Notification] Earliest notification instance
181
+ def self.earliest!
182
+ earliest
183
+ end
133
184
 
134
- # Orders by earliest (older) first as created_at: :asc.
135
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
136
- scope :earliest_order, -> { order(created_at: :asc) }
185
+ # Selects unique keys from query for notifications.
186
+ # @return [Array<String>] Array of notification unique keys
187
+ def self.uniq_keys
188
+ ## select method cannot be chained with order by other columns like created_at
189
+ # select(:key).distinct.pluck(:key)
190
+ ## distinct method cannot keep original sort
191
+ # distinct(:key)
192
+ pluck(:key).uniq
193
+ end
194
+ end
195
+ # :nocov:
137
196
  end
138
197
 
139
198
  class_methods do
@@ -157,6 +216,7 @@ module ActivityNotification
157
216
  # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
158
217
  # @option options [Object] :notifier (nil) Notifier of the notifications
159
218
  # @option options [Hash] :parameters ({}) Additional parameters of the notifications
219
+ # @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously
160
220
  # @option options [Boolean] :send_email (true) Whether it sends notification email
161
221
  # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
162
222
  # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
@@ -164,11 +224,48 @@ module ActivityNotification
164
224
  # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
165
225
  # @return [Array<Notificaion>] Array of generated notifications
166
226
  def notify(target_type, notifiable, options = {})
167
- targets = notifiable.notification_targets(target_type, options[:pass_full_options] ? options : options[:key])
168
- unless targets.blank?
169
- notify_all(targets, notifiable, options)
227
+ if options[:notify_later]
228
+ notify_later(target_type, notifiable, options)
229
+ else
230
+ targets = notifiable.notification_targets(target_type, options[:pass_full_options] ? options : options[:key])
231
+ unless targets.blank?
232
+ notify_all(targets, notifiable, options)
233
+ end
170
234
  end
171
235
  end
236
+ alias_method :notify_now, :notify
237
+
238
+ # Generates notifications to configured targets with notifiable model later by ActiveJob queue.
239
+ #
240
+ # @example Use with target_type as Symbol
241
+ # ActivityNotification::Notification.notify_later :users, @comment
242
+ # @example Use with target_type as String
243
+ # ActivityNotification::Notification.notify_later 'User', @comment
244
+ # @example Use with target_type as Class
245
+ # ActivityNotification::Notification.notify_later User, @comment
246
+ # @example Use with options
247
+ # ActivityNotification::Notification.notify_later :users, @comment, key: 'custom.comment', group: @comment.article
248
+ # ActivityNotification::Notification.notify_later :users, @comment, parameters: { reply_to: @comment.reply_to }, send_later: false
249
+ #
250
+ # @param [Symbol, String, Class] target_type Type of target
251
+ # @param [Object] notifiable Notifiable instance
252
+ # @param [Hash] options Options for notifications
253
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
254
+ # @option options [Object] :group (nil) Group unit of the notifications
255
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
256
+ # @option options [Object] :notifier (nil) Notifier of the notifications
257
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
258
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
259
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
260
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
261
+ # @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only
262
+ # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
263
+ # @return [Array<Notificaion>] Array of generated notifications
264
+ def notify_later(target_type, notifiable, options = {})
265
+ target_type = target_type.to_s if target_type.is_a? Symbol
266
+ options.delete(:notify_later)
267
+ ActivityNotification::NotifyJob.perform_later(target_type, notifiable, options)
268
+ end
172
269
 
173
270
  # Generates notifications to specified targets.
174
271
  #
@@ -183,13 +280,42 @@ module ActivityNotification
183
280
  # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
184
281
  # @option options [Object] :notifier (nil) Notifier of the notifications
185
282
  # @option options [Hash] :parameters ({}) Additional parameters of the notifications
283
+ # @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously
186
284
  # @option options [Boolean] :send_email (true) Whether it sends notification email
187
285
  # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
188
286
  # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
189
287
  # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
190
288
  # @return [Array<Notificaion>] Array of generated notifications
191
289
  def notify_all(targets, notifiable, options = {})
192
- targets.map { |target| target.notify_to(notifiable, options) }
290
+ if options[:notify_later]
291
+ notify_all_later(targets, notifiable, options)
292
+ else
293
+ targets.map { |target| notify_to(target, notifiable, options) }
294
+ end
295
+ end
296
+ alias_method :notify_all_now, :notify_all
297
+
298
+ # Generates notifications to specified targets later by ActiveJob queue.
299
+ #
300
+ # @example Notify to all users later
301
+ # ActivityNotification::Notification.notify_all_later User.all, @comment
302
+ #
303
+ # @param [Array<Object>] targets Targets to send notifications
304
+ # @param [Object] notifiable Notifiable instance
305
+ # @param [Hash] options Options for notifications
306
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
307
+ # @option options [Object] :group (nil) Group unit of the notifications
308
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
309
+ # @option options [Object] :notifier (nil) Notifier of the notifications
310
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
311
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
312
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
313
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
314
+ # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
315
+ # @return [Array<Notificaion>] Array of generated notifications
316
+ def notify_all_later(targets, notifiable, options = {})
317
+ options.delete(:notify_later)
318
+ ActivityNotification::NotifyAllJob.perform_later(targets, notifiable, options)
193
319
  end
194
320
 
195
321
  # Generates notifications to one target.
@@ -205,27 +331,56 @@ module ActivityNotification
205
331
  # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
206
332
  # @option options [Object] :notifier (nil) Notifier of the notifications
207
333
  # @option options [Hash] :parameters ({}) Additional parameters of the notifications
334
+ # @option options [Boolean] :notify_later (false) Whether it generates notifications asynchronously
208
335
  # @option options [Boolean] :send_email (true) Whether it sends notification email
209
336
  # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
210
337
  # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
211
338
  # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
212
339
  # @return [Notification] Generated notification instance
213
340
  def notify_to(target, notifiable, options = {})
214
- send_email = options.has_key?(:send_email) ? options[:send_email] : true
215
- send_later = options.has_key?(:send_later) ? options[:send_later] : true
216
- publish_optional_targets = options.has_key?(:publish_optional_targets) ? options[:publish_optional_targets] : true
217
- # Generate notification
218
- notification = generate_notification(target, notifiable, options)
219
- # Send notification email
220
- if notification.present? && send_email
221
- notification.send_notification_email({ send_later: send_later })
222
- end
223
- # Publish to optional targets
224
- if notification.present? && publish_optional_targets
225
- notification.publish_to_optional_targets(options[:optional_targets] || {})
341
+ if options[:notify_later]
342
+ notify_later_to(target, notifiable, options)
343
+ else
344
+ send_email = options.has_key?(:send_email) ? options[:send_email] : true
345
+ send_later = options.has_key?(:send_later) ? options[:send_later] : true
346
+ publish_optional_targets = options.has_key?(:publish_optional_targets) ? options[:publish_optional_targets] : true
347
+ # Generate notification
348
+ notification = generate_notification(target, notifiable, options)
349
+ # Send notification email
350
+ if notification.present? && send_email
351
+ notification.send_notification_email({ send_later: send_later })
352
+ end
353
+ # Publish to optional targets
354
+ if notification.present? && publish_optional_targets
355
+ notification.publish_to_optional_targets(options[:optional_targets] || {})
356
+ end
357
+ # Return generated notification
358
+ notification
226
359
  end
227
- # Return generated notification
228
- notification
360
+ end
361
+ alias_method :notify_now_to, :notify_to
362
+
363
+ # Generates notifications to one target later by ActiveJob queue.
364
+ #
365
+ # @example Notify to one user later
366
+ # ActivityNotification::Notification.notify_later_to @comment.auther, @comment
367
+ #
368
+ # @param [Object] target Target to send notifications
369
+ # @param [Object] notifiable Notifiable instance
370
+ # @param [Hash] options Options for notifications
371
+ # @option options [String] :key (notifiable.default_notification_key) Key of the notification
372
+ # @option options [Object] :group (nil) Group unit of the notifications
373
+ # @option options [ActiveSupport::Duration] :group_expiry_delay (nil) Expiry period of a notification group
374
+ # @option options [Object] :notifier (nil) Notifier of the notifications
375
+ # @option options [Hash] :parameters ({}) Additional parameters of the notifications
376
+ # @option options [Boolean] :send_email (true) Whether it sends notification email
377
+ # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
378
+ # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
379
+ # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
380
+ # @return [Notification] Generated notification instance
381
+ def notify_later_to(target, notifiable, options = {})
382
+ options.delete(:notify_later)
383
+ ActivityNotification::NotifyToJob.perform_later(target, notifiable, options)
229
384
  end
230
385
 
231
386
  # Generates a notification
@@ -240,7 +395,7 @@ module ActivityNotification
240
395
  key = options[:key] || notifiable.default_notification_key
241
396
  if target.subscribes_to_notification?(key)
242
397
  # Store notification
243
- store_notification(target, notifiable, key, options)
398
+ notification = store_notification(target, notifiable, key, options)
244
399
  end
245
400
  end
246
401
 
@@ -254,14 +409,15 @@ module ActivityNotification
254
409
  # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
255
410
  # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
256
411
  # @option options [String] :filtered_by_key (nil) Key of the notification for filter
257
- # @return [Integer] Number of opened notification records
258
- # @todo Add filter option
412
+ # @option options [String] :later_than (nil) ISO 8601 format time to filter notification index later than specified time
413
+ # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notification index earlier than specified time
414
+ # @return [Array<Notification>] Opened notification records
259
415
  def open_all_of(target, options = {})
260
416
  opened_at = options[:opened_at] || Time.current
261
417
  target_unopened_notifications = target.notifications.unopened_only.filtered_by_options(options)
262
- unopened_notification_count = target_unopened_notifications.count
418
+ opened_notifications = target_unopened_notifications.to_a.map { |n| n.opened_at = opened_at; n }
263
419
  target_unopened_notifications.update_all(opened_at: opened_at)
264
- unopened_notification_count
420
+ opened_notifications
265
421
  end
266
422
 
267
423
  # Returns if group member of the notifications exists.
@@ -270,7 +426,7 @@ module ActivityNotification
270
426
  # @param [Array<Notificaion>, ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] notifications Array or database query of the notifications to test member exists
271
427
  # @return [Boolean] If group member of the notifications exists
272
428
  def group_member_exists?(notifications)
273
- notifications.present? && group_members_of_owner_ids_only(notifications.map(&:id)).exists?
429
+ notifications.present? and group_members_of_owner_ids_only(notifications.map(&:id)).exists?
274
430
  end
275
431
 
276
432
  # Sends batch notification email to the target.
@@ -298,7 +454,7 @@ module ActivityNotification
298
454
  #
299
455
  # @return [Array<Notificaion>] Available options for kinds of notify methods
300
456
  def available_options
301
- [:key, :group, :parameters, :notifier, :send_email, :send_later].freeze
457
+ [:key, :group, :group_expiry_delay, :notifier, :parameters, :send_email, :send_later, :pass_full_options].freeze
302
458
  end
303
459
 
304
460
  # Defines mailer class to send notification
@@ -306,6 +462,25 @@ module ActivityNotification
306
462
  @@notification_mailer = ActivityNotification.config.mailer.constantize
307
463
  end
308
464
 
465
+ # Returns valid group owner within the expiration period
466
+ #
467
+ # @param [Object] target Target to send notifications
468
+ # @param [Object] notifiable Notifiable instance
469
+ # @param [String] key Key of the notification
470
+ # @param [Object] group Group unit of the notifications
471
+ # @param [ActiveSupport::Duration] group_expiry_delay Expiry period of a notification group
472
+ # @return [Notificaion] Valid group owner within the expiration period
473
+ def valid_group_owner(target, notifiable, key, group, group_expiry_delay)
474
+ return nil if group.blank?
475
+ # Bundle notification group by target, notifiable_type, group and key
476
+ # Different notifiable.id can be made in a same group
477
+ group_owner_notifications = filtered_by_target(target).filtered_by_type(notifiable.to_class_name).filtered_by_key(key)
478
+ .filtered_by_group(group).group_owners_only.unopened_only
479
+ group_expiry_delay.present? ?
480
+ group_owner_notifications.within_expiration_only(group_expiry_delay).earliest :
481
+ group_owner_notifications.earliest
482
+ end
483
+
309
484
  # Stores notifications to datastore
310
485
  # @api private
311
486
  def store_notification(target, notifiable, key, options = {})
@@ -316,20 +491,27 @@ module ActivityNotification
316
491
  parameters = options[:parameters] || {}
317
492
  parameters.merge!(options.except(*available_options))
318
493
  parameters.merge!(notifiable.notification_parameters(target_type, key))
494
+ group_owner = valid_group_owner(target, notifiable, key, group, group_expiry_delay)
319
495
 
320
- # Bundle notification group by target, notifiable_type, group and key
321
- # Different notifiable.id can be made in a same group
322
- group_owner_notifications = filtered_by_target(target).filtered_by_type(notifiable.to_class_name).filtered_by_key(key)
323
- .filtered_by_group(group).group_owners_only.unopened_only
324
- group_owner = group_expiry_delay.present? ?
325
- group_owner_notifications.within_expiration_only(group_expiry_delay).earliest :
326
- group_owner_notifications.earliest
327
- notification_fields = { target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier }
328
- notification_fields = notification_fields.merge(group_owner: group_owner) if group.present? && group_owner.present?
329
- create(notification_fields)
496
+ notification = new({ target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier, group_owner: group_owner })
497
+ notification.prepare_to_store.save
498
+ notification.after_store
499
+ notification
330
500
  end
331
501
  end
332
502
 
503
+ # :nocov:
504
+ # Returns prepared notification object to store
505
+ # @return [Object] prepared notification object to store
506
+ def prepare_to_store
507
+ self
508
+ end
509
+
510
+ # Call after store action with stored notification
511
+ def after_store
512
+ end
513
+ # :nocov:
514
+
333
515
  # Sends notification email to the target.
334
516
  #
335
517
  # @param [Hash] options Options for notification email
@@ -355,8 +537,17 @@ module ActivityNotification
355
537
  notifiable.optional_targets(target.to_resources_name, key).map { |optional_target|
356
538
  optional_target_name = optional_target.to_optional_target_name
357
539
  if optional_target_subscribed?(optional_target_name)
358
- optional_target.notify(self, options[optional_target_name] || {})
359
- [optional_target_name, true]
540
+ begin
541
+ optional_target.notify(self, options[optional_target_name] || {})
542
+ [optional_target_name, true]
543
+ rescue => e
544
+ Rails.logger.error(e)
545
+ if ActivityNotification.config.rescue_optional_target_errors
546
+ [optional_target_name, e]
547
+ else
548
+ raise e
549
+ end
550
+ end
360
551
  else
361
552
  [optional_target_name, false]
362
553
  end
@@ -492,10 +683,16 @@ module ActivityNotification
492
683
  #
493
684
  # @return [String] Notifiable path URL to move after opening notification
494
685
  def notifiable_path
495
- notifiable.present? or raise ActiveRecord::RecordNotFound.new("Couldn't find notifiable #{notifiable_type}")
686
+ notifiable.blank? and raise ActivityNotification::NotifiableNotFoundError.new("Couldn't find associated notifiable (#{notifiable_type}) of #{self.class.name} with 'id'=#{id}")
496
687
  notifiable.notifiable_path(target_type, key)
497
688
  end
498
689
 
690
+ # Returns printable notifiable model name to show in view or email.
691
+ # @return [String] Printable notifiable model name
692
+ def printable_notifiable_name
693
+ notifiable.printable_notifiable_name(target, key)
694
+ end
695
+
499
696
  # Returns if the target subscribes this notification.
500
697
  # @return [Boolean] If the target subscribes the notification
501
698
  def subscribed?
@@ -515,13 +712,13 @@ module ActivityNotification
515
712
  target.subscribes_to_optional_target?(key, optional_target_name)
516
713
  end
517
714
 
518
- # Returns optional_targets of the notification from configured field or overriden method.
715
+ # Returns optional_targets of the notification from configured field or overridden method.
519
716
  # @return [Array<ActivityNotification::OptionalTarget::Base>] Array of optional target instances
520
717
  def optional_targets
521
718
  notifiable.optional_targets(target.to_resources_name, key)
522
719
  end
523
720
 
524
- # Returns optional_target names of the notification from configured field or overriden method.
721
+ # Returns optional_target names of the notification from configured field or overridden method.
525
722
  # @return [Array<Symbol>] Array of optional target names
526
723
  def optional_target_names
527
724
  notifiable.optional_target_names(target.to_resources_name, key)