activity_notification 1.4.4 → 2.2.4

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