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
data/docs/Functions.md ADDED
@@ -0,0 +1,1146 @@
1
+ ## Functions
2
+
3
+ ### Email notification
4
+
5
+ *activity_notification* provides email notification to the notification targets.
6
+
7
+ #### Mailer setup
8
+
9
+ Set up SMTP server configuration for *ActionMailer*. Then, you need to set up the default URL options for the *activity_notification* mailer in each environment. Here is a possible configuration for *config/environments/development.rb*:
10
+
11
+ ```ruby
12
+ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
13
+ ```
14
+
15
+ Email notification is disabled as default. You can configure it to enable email notification in initializer *activity_notification.rb*.
16
+
17
+ ```ruby
18
+ config.email_enabled = true
19
+ ```
20
+
21
+ You can also configure them for each model by *acts_as roles* like these:
22
+
23
+ ```ruby
24
+ class User < ActiveRecord::Base
25
+ # Example using confirmed_at of devise field
26
+ # to decide whether activity_notification sends notification email to this user
27
+ acts_as_target email: :email, email_allowed: :confirmed_at
28
+ end
29
+ ```
30
+
31
+ ```ruby
32
+ class Comment < ActiveRecord::Base
33
+ belongs_to :article
34
+ belongs_to :user
35
+
36
+ acts_as_notifiable :users,
37
+ targets: ->(comment, key) {
38
+ ([comment.article.user] + comment.article.reload.commented_users.to_a - [comment.user]).uniq
39
+ },
40
+ # Allow notification email
41
+ email_allowed: true,
42
+ notifiable_path: :article_notifiable_path
43
+
44
+ def article_notifiable_path
45
+ article_path(article)
46
+ end
47
+ end
48
+ ```
49
+
50
+ #### Sender configuration
51
+
52
+ You can configure the notification *"from"* address inside of *activity_notification.rb* in two ways.
53
+
54
+ Using a simple email address as *String*:
55
+
56
+ ```ruby
57
+ config.mailer_sender = 'your_notification_sender@example.com'
58
+ ```
59
+
60
+ Using a *Proc* to configure the sender based on the *notification.key*:
61
+
62
+ ```ruby
63
+ config.mailer_sender = ->(key){ key == 'inquiry.post' ? 'support@example.com' : 'noreply@example.com' }
64
+ ```
65
+
66
+ #### Email templates
67
+
68
+ *activity_notification* will look for email template in a similar way as notification views, but the view file name does not start with an underscore. For example, if you have a notification with *:key* set to *"notification.comment.reply"* and target_type *users*, the gem will look for a partial in *app/views/activity_notification/mailer/users/comment/reply.html.(|erb|haml|slim|something_else)*.
69
+
70
+ If this template is missing, the gem will use *default* as the target type which means *activity_notification/mailer/default/default.html.(|erb|haml|slim|something_else)*.
71
+
72
+ #### Email subject
73
+
74
+ *activity_notification* will use `"Notification of #{@notification.notifiable.printable_type.downcase}"` as default email subject. If it is defined, *activity_notification* will resolve email subject from *overriding_notification_email_subject* method in notifiable models. You can customize email subject like this:
75
+
76
+ ```ruby
77
+ class Comment < ActiveRecord::Base
78
+ belongs_to :article
79
+ belongs_to :user
80
+
81
+ acts_as_notifiable :users,
82
+ targets: ->(comment, key) {
83
+ ([comment.article.user] + comment.article.reload.commented_users.to_a - [comment.user]).uniq
84
+ },
85
+ notifiable_path: :article_notifiable_path
86
+
87
+ def overriding_notification_email_subject(target, key)
88
+ if key == "comment.create"
89
+ "New comment to your article!"
90
+ else
91
+ "Notification for new comments!"
92
+ end
93
+ end
94
+ end
95
+
96
+ ```
97
+
98
+ If you use i18n for email, you can configure email subject in your locale files. See [i18n for email](#i18n-for-email).
99
+
100
+ #### Other header fields
101
+
102
+ Similarly to the [Email subject](#email-subject), the `From`, `Reply-To` and `Message-ID` headers are configurable per notifiable model. From and reply to will override the `config.mailer_sender` config setting.
103
+
104
+ ```ruby
105
+ class Comment < ActiveRecord::Base
106
+ belongs_to :article
107
+ belongs_to :user
108
+
109
+ acts_as_notifiable :users,
110
+ targets: ->(comment, key) {
111
+ ([comment.article.user] + comment.article.commented_users.to_a - [comment.user]).uniq
112
+ },
113
+ notifiable_path: :article_notifiable_path
114
+
115
+ def overriding_notification_email_from(target, key)
116
+ "no-reply.article@example.com"
117
+ end
118
+
119
+ def overriding_notification_email_reply_to(target, key)
120
+ "no-reply.article+comment-#{self.id}@example.com"
121
+ end
122
+
123
+ def overriding_notification_email_message_id(target, key)
124
+ "https://www.example.com/article/#{article.id}@example.com/"
125
+ end
126
+ end
127
+ ```
128
+
129
+ #### i18n for email
130
+
131
+ The subject of notification email can be put in your locale *.yml* files as **mail_subject** field:
132
+
133
+ ```yaml
134
+ notification:
135
+ user:
136
+ comment:
137
+ post:
138
+ text: "<p>Someone posted comments to your article</p>"
139
+ mail_subject: 'New comment to your article'
140
+ ```
141
+
142
+ ### Batch email notification
143
+
144
+ *activity_notification* provides batch email notification to the notification targets. You can send notification email daily, hourly or weekly and so on with a scheduler like *whenever*.
145
+
146
+ #### Batch mailer setup
147
+
148
+ Set up SMTP server configuration for *ActionMailer* and the default URL options for the *activity_notification* mailer in each environment.
149
+
150
+ Batch email notification is disabled as default. You can configure it to enable email notification in initializer *activity_notification.rb* like single email notification.
151
+
152
+ ```ruby
153
+ config.email_enabled = true
154
+ ```
155
+
156
+ You can also configure them for each target model by *acts_as_target* role like this.
157
+
158
+ ```ruby
159
+ class User < ActiveRecord::Base
160
+ # Example using confirmed_at of devise field
161
+ # to decide whether activity_notification sends batch notification email to this user
162
+ acts_as_target email: :email, batch_email_allowed: :confirmed_at
163
+ end
164
+ ```
165
+
166
+ Then, you can send batch notification email for unopened notifications only to the all specified targets with *batch_key*.
167
+
168
+ ```ruby
169
+ # Send batch notification email to the users with unopened notifications
170
+ User.send_batch_unopened_notification_email(batch_key: 'batch.comment.post')
171
+ ```
172
+
173
+ You can also add conditions to filter notifications, like this:
174
+
175
+ ```ruby
176
+ # Send batch notification email to the users with unopened notifications of specified key in 1 hour
177
+ User.send_batch_unopened_notification_email(batch_key: 'batch.comment.post', filtered_by_key: 'comment.post', custom_filter: ["created_at >= ?", time.hour.ago])
178
+ ```
179
+
180
+ #### Batch sender configuration
181
+
182
+ *activity_notification* uses same sender configuration of real-time email notification as batch email sender.
183
+ You can configure *config.mailer_sender* as simply *String* or *Proc* based on the *batch_key*:
184
+
185
+ ```ruby
186
+ config.mailer_sender = ->(batch_key){ batch_key == 'batch.inquiry.post' ? 'support@example.com' : 'noreply@example.com' }
187
+ ```
188
+
189
+ *batch_key* is specified by **:batch_key** option. If this option is not specified, the key of the first notification will be used as *batch_key*.
190
+
191
+ #### Batch email templates
192
+
193
+ *activity_notification* will look for batch email template in the same way as email notification using *batch_key*.
194
+
195
+ #### Batch email subject
196
+
197
+ *activity_notification* will resolve batch email subject as the same way as [email subject](#email-subject) with *batch_key*.
198
+
199
+ If you use i18n for batch email, you can configure batch email subject in your locale files. See [i18n for batch email](#i18n-for-batch-email).
200
+
201
+ #### i18n for batch email
202
+
203
+ The subject of batch notification email also can be put in your locale *.yml* files as **mail_subject** field for *batch_key*.
204
+
205
+ ```yaml
206
+ notification:
207
+ user:
208
+ batch:
209
+ comment:
210
+ post:
211
+ mail_subject: 'New comments to your article'
212
+ ```
213
+
214
+ ### Grouping notifications
215
+
216
+ *activity_notification* provides the function for automatically grouping notifications. When you created a notification like this, all *unopened* notifications to the same target will be grouped by *article* set as **:group** options:
217
+
218
+ ```ruby
219
+ @comment.notify :users key: 'comment.post', group: @comment.article
220
+ ```
221
+
222
+ When you use default notification view, it is helpful to configure **acts_as_notification_group** (or *acts_as_group*) with *:printable_name* option to render group instance.
223
+
224
+ ```ruby
225
+ class Article < ActiveRecord::Base
226
+ belongs_to :user
227
+ acts_as_notification_group printable_name: ->(article) { "article \"#{article.title}\"" }
228
+ end
229
+ ```
230
+
231
+ You can use **group_owners_only** scope to filter owner notifications representing each group:
232
+
233
+ ```ruby
234
+ # custom_notifications_controller.rb
235
+ def index
236
+ @notifications = @target.notifications.group_owners_only
237
+ end
238
+ ```
239
+ *notification_index* and *notification_index_with_attributes* methods also use *group_owners_only* scope internally.
240
+
241
+ And you can render them in a view like this:
242
+ ```erb
243
+ <% if notification.group_member_exists? %>
244
+ <%= "#{notification.notifier.name} and #{notification.group_member_count} other users" %>
245
+ <% else %>
246
+ <%= "#{notification.notifier.name}" %>
247
+ <% end %>
248
+ <%= "posted comments to your article \"#{notification.group.title}\"" %>
249
+ ```
250
+
251
+ This presentation will be shown to target users as *Kevin and 7 other users posted comments to your article "Let's use Ruby"*.
252
+
253
+ You can also use `%{group_member_count}`, `%{group_notification_count}`, `%{group_member_notifier_count}` and `%{group_notifier_count}` in i18n text as a field:
254
+
255
+ ```yaml
256
+ notification:
257
+ user:
258
+ comment:
259
+ post:
260
+ text: "<p>%{notifier_name} and %{group_member_notifier_count} other users posted %{group_notification_count} comments to your article</p>"
261
+ mail_subject: 'New comment to your article'
262
+ ```
263
+
264
+ Then, you will see *"Kevin and 7 other users posted 10 comments to your article"*.
265
+
266
+
267
+ ### Subscription management
268
+
269
+ *activity_notification* provides the function for subscription management of notifications and notification email.
270
+
271
+ #### Configuring subscriptions
272
+
273
+ Subscription management is disabled as default. You can configure it to enable subscription management in initializer *activity_notification.rb*.
274
+
275
+ ```ruby
276
+ config.subscription_enabled = true
277
+ ```
278
+
279
+ This makes all target model subscribers. You can also configure them for each target model by *acts_as_target* role like this:
280
+
281
+ ```ruby
282
+ class User < ActiveRecord::Base
283
+ # Example using confirmed_at of devise field
284
+ # to decide whether activity_notification manages subscriptions of this user
285
+ acts_as_target email: :email, email_allowed: :confirmed_at, subscription_allowed: :confirmed_at
286
+ end
287
+ ```
288
+
289
+ If you do not have a subscriptions table in you database, create a migration for subscriptions and migrate the database in your Rails project:
290
+
291
+ ```console
292
+ $ bin/rails generate activity_notification:migration CreateSubscriptions -t subscriptions
293
+ $ bin/rake db:migrate
294
+ ```
295
+ If you are using a different table name than the default "subscriptions", change the settings in your config/initializers/activity_notification.rb file, e.g, if you use the table name "notifications_subscription" instead:
296
+
297
+ ```
298
+ config.subscription_table_name = "notifications_subscriptions"
299
+ ```
300
+
301
+ #### Managing subscriptions
302
+
303
+ Subscriptions are managed by instances of **ActivityNotification::Subscription** model which belongs to *target* and *key* of the notification.
304
+ *Subscription#subscribing* manages subscription of notifications.
305
+ *true* means the target will receive the notifications with this key.
306
+ *false* means the target will not receive these notifications.
307
+ *Subscription#subscribing_to_email* manages subscription of notification email.
308
+ *true* means the target will receive the notification email with this key including batch notification email with this *batch_key*.
309
+ *false* means the target will not receive these notification email.
310
+
311
+ ##### Subscription defaults
312
+
313
+ As default, all target subscribes to notification and notification email when subscription record does not exist in your database.
314
+ You can change this **subscribe_as_default** parameter in initializer *activity_notification.rb*.
315
+
316
+ ```ruby
317
+ config.subscribe_as_default = false
318
+ ```
319
+
320
+ Then, all target does not subscribe to notification and notification email and will not receive any notifications as default.
321
+
322
+ As default, email and optional target subscriptions will use the same default subscription value as defined in **subscribe_as_default**.
323
+ You can disable them by providing **subscribe_to_email_as_default** or **subscribe_to_optional_targets_as_default** parameter(s) in initializer *activity_notification.rb*.
324
+
325
+ ```ruby
326
+ # Enable subscribe as default, but disable it for emails
327
+ config.subscribe_as_default = true
328
+ config.subscribe_to_email_as_default = false
329
+ config.subscribe_to_optional_targets_as_default = true
330
+ ```
331
+
332
+ However if **subscribe_as_default** is not enabled, **subscribe_to_email_as_default** and **subscribe_to_optional_targets_as_default** won't change anything.
333
+
334
+ ##### Creating and updating subscriptions
335
+
336
+ You can create subscription record from subscription API in your target model like this:
337
+
338
+ ```ruby
339
+ # Subscribe 'comment.reply' notifications and notification email
340
+ user.create_subscription(key: 'comment.reply')
341
+
342
+ # Subscribe 'comment.reply' notifications but does not subscribe notification email
343
+ user.create_subscription(key: 'comment.reply', subscribing_to_email: false)
344
+
345
+ # Unsubscribe 'comment.reply' notifications and notification email
346
+ user.create_subscription(key: 'comment.reply', subscribing: false)
347
+ ```
348
+
349
+ You can also update subscriptions like this:
350
+
351
+ ```ruby
352
+ # Subscribe 'comment.reply' notifications and notification email
353
+ user.find_or_create_subscription('comment.reply').subscribe
354
+
355
+ # Unsubscribe 'comment.reply' notifications and notification email
356
+ user.find_or_create_subscription('comment.reply').unsubscribe
357
+
358
+ # Unsubscribe 'comment.reply' notification email
359
+ user.find_or_create_subscription('comment.reply').unsubscribe_to_email
360
+ ```
361
+
362
+ #### Customizing subscriptions
363
+
364
+ *activity_notification* provides basic controllers and views to manage the subscriptions.
365
+
366
+ Add subscription routing to *config/routes.rb* for the target (e.g. *:users*):
367
+
368
+ ```ruby
369
+ Rails.application.routes.draw do
370
+ subscribed_by :users
371
+ end
372
+ ```
373
+
374
+ or, you can also configure it with notifications like this:
375
+
376
+ ```ruby
377
+ Rails.application.routes.draw do
378
+ notify_to :users, with_subscription: true
379
+ end
380
+ ```
381
+
382
+ Then, you can access *users/1/subscriptions* and use *[ActivityNotification::SubscriptionsController](/app/controllers/activity_notification/subscriptions_controller.rb)* or *[ActivityNotification::SubscriptionsWithDeviseController](/app/controllers/activity_notification/subscriptions_with_devise_controller.rb)* to manage the subscriptions.
383
+
384
+ You can see sample subscription management view in demo application here: *https://activity-notification-example.herokuapp.com/users/1/subscriptions*
385
+
386
+ If you would like to customize subscription controllers or views, you can use generators like notifications:
387
+
388
+ * Customize subscription controllers
389
+
390
+ 1. Create your custom controllers using controller generator with a target:
391
+
392
+ ```console
393
+ $ bin/rails generate activity_notification:controllers users -c subscriptions subscriptions_with_devise
394
+ ```
395
+
396
+ 2. Tell the router to use this controller:
397
+
398
+ ```ruby
399
+ notify_to :users, with_subscription: { controller: 'users/subscriptions' }
400
+ ```
401
+
402
+ * Customize subscription views
403
+
404
+ ```console
405
+ $ bin/rails generate activity_notification:views users -v subscriptions
406
+ ```
407
+
408
+
409
+ ### REST API backend
410
+
411
+ *activity_notification* provides REST API backend to operate notifications and subscriptions.
412
+
413
+ #### Configuring REST API backend
414
+
415
+ You can configure *activity_notification* routes as REST API backend with **:api_mode** option of *notify_to* method. See [Routes as REST API backend](#routes-as-rest-api-backend) for more details. With *:api_mode* option, *activity_notification* uses *[ActivityNotification::NotificationsApiController](/app/controllers/activity_notification/notifications_api_controller.rb)* instead of *[ActivityNotification::NotificationsController](/app/controllers/activity_notification/notifications_controller.rb)*.
416
+
417
+ In addition, you can use *:with_subscription* option with *:api_mode* to enable subscription management like this:
418
+
419
+ ```ruby
420
+ Rails.application.routes.draw do
421
+ scope :api do
422
+ scope :"v2" do
423
+ notify_to :users, api_mode: true, with_subscription: true
424
+ end
425
+ end
426
+ end
427
+ ```
428
+
429
+ Then, *activity_notification* uses *[ActivityNotification::SubscriptionsApiController](/app/controllers/activity_notification/subscriptions_api_controller.rb)* instead of *[ActivityNotification::SubscriptionsController](/app/controllers/activity_notification/subscriptions_controller.rb)*, and you can call *activity_notification* REST API as */api/v2/notifications* and */api/v2/subscriptions* from your frontend application.
430
+
431
+ When you want to use REST API backend integrated with Devise authentication, see [REST API backend with Devise Token Auth](#rest-api-backend-with-devise-token-auth).
432
+
433
+ You can see [sample single page application](/spec/rails_app/app/javascript/) using [Vue.js](https://vuejs.org) as a part of example Rails application. This sample application works with *activity_notification* REST API backend.
434
+
435
+ #### API reference as OpenAPI Specification
436
+
437
+ *activity_notification* provides API reference as [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification).
438
+
439
+ OpenAPI Specification in [online demo](https://activity-notification-example.herokuapp.com/) is published here: **https://activity-notification-example.herokuapp.com/api/v2/apidocs**
440
+
441
+ Public API reference is also hosted in [SwaggerHub](https://swagger.io/tools/swaggerhub/) here: **https://app.swaggerhub.com/apis-docs/simukappu/activity-notification/**
442
+
443
+ You can also publish OpenAPI Specification in your own application using *[ActivityNotification::ApidocsController](/app/controllers/activity_notification/apidocs_controller.rb)* like this:
444
+
445
+ ```ruby
446
+ Rails.application.routes.draw do
447
+ scope :api do
448
+ scope :"v2" do
449
+ resources :apidocs, only: [:index], controller: 'activity_notification/apidocs'
450
+ end
451
+ end
452
+ end
453
+ ```
454
+
455
+ You can use [Swagger UI](https://swagger.io/tools/swagger-ui/) with this OpenAPI Specification to visualize and interact with *activity_notification* API’s resources.
456
+
457
+
458
+ ### Integration with Devise
459
+
460
+ *activity_notification* supports to integrate with devise authentication.
461
+
462
+ #### Configuring integration with Devise authentication
463
+
464
+ Add **:with_devise** option in notification routing to *config/routes.rb* for the target:
465
+
466
+ ```ruby
467
+ Rails.application.routes.draw do
468
+ devise_for :users
469
+ # Integrated with Devise
470
+ notify_to :users, with_devise: :users
471
+ end
472
+ ```
473
+
474
+ Then *activity_notification* will use *[ActivityNotification::NotificationsWithDeviseController](/app/controllers/activity_notification/notifications_with_devise_controller.rb)* as a notifications controller. The controller actions automatically call *authenticate_user!* and the user will be restricted to access and operate own notifications only, not others'.
475
+
476
+ *Hint*: HTTP 403 Forbidden will be returned for unauthorized notifications.
477
+
478
+ #### Using different model as target
479
+
480
+ You can also use different model from Devise resource as a target. When you will add this to *config/routes.rb*:
481
+
482
+ ```ruby
483
+ Rails.application.routes.draw do
484
+ devise_for :users
485
+ # Integrated with Devise for different model
486
+ notify_to :admins, with_devise: :users
487
+ end
488
+ ```
489
+
490
+ and add **:devise_resource** option to *acts_as_target* in the target model:
491
+
492
+ ```ruby
493
+ class Admin < ActiveRecord::Base
494
+ belongs_to :user
495
+ acts_as_target devise_resource: :user
496
+ end
497
+ ```
498
+
499
+ *activity_notification* will authenticate *:admins* notifications with devise authentication for *:users*.
500
+ In this example, *activity_notification* will confirm *admin* belonging to authenticated *user* by Devise.
501
+
502
+ #### Configuring simple default routes
503
+
504
+ You can configure simple default routes for authenticated users, like */notifications* instead of */users/1/notifications*. Use **:devise_default_routes** option like this:
505
+
506
+ ```ruby
507
+ Rails.application.routes.draw do
508
+ devise_for :users
509
+ notify_to :users, with_devise: :users, devise_default_routes: true
510
+ end
511
+ ```
512
+
513
+ If you use multiple notification targets with Devise, you can also use this option with scope like this:
514
+
515
+ ```ruby
516
+ Rails.application.routes.draw do
517
+ devise_for :users
518
+ # Integrated with Devise for different model, and use with scope
519
+ scope :admins, as: :admins do
520
+ notify_to :admins, with_devise: :users, devise_default_routes: true, routing_scope: :admins
521
+ end
522
+ end
523
+ ```
524
+
525
+ Then, you can access */admins/notifications* instead of */admins/1/notifications*.
526
+
527
+ #### REST API backend with Devise Token Auth
528
+
529
+ We can also integrate [REST API backend](#rest-api-backend) with [Devise Token Auth](https://github.com/lynndylanhurley/devise_token_auth).
530
+ Use **:with_devise** option with **:api_mode** option *config/routes.rb* for the target like this:
531
+
532
+ ```ruby
533
+ Rails.application.routes.draw do
534
+ devise_for :users
535
+ # Configure authentication API with Devise Token Auth
536
+ namespace :api do
537
+ scope :"v2" do
538
+ mount_devise_token_auth_for 'User', at: 'auth'
539
+ end
540
+ end
541
+ # Integrated with Devise Token Auth
542
+ scope :api do
543
+ scope :"v2" do
544
+ notify_to :users, api_mode: true, with_devise: :users, with_subscription: true
545
+ end
546
+ end
547
+ end
548
+ ```
549
+
550
+ You can also configure it as simple default routes and with different model from Devise resource as a target:
551
+
552
+ ```ruby
553
+ Rails.application.routes.draw do
554
+ devise_for :users
555
+ # Configure authentication API with Devise Token Auth
556
+ namespace :api do
557
+ scope :"v2" do
558
+ mount_devise_token_auth_for 'User', at: 'auth'
559
+ end
560
+ end
561
+ # Integrated with Devise Token Auth as simple default routes and with different model from Devise resource as a target
562
+ scope :api do
563
+ scope :"v2" do
564
+ scope :admins, as: :admins do
565
+ notify_to :admins, api_mode: true, with_devise: :users, devise_default_routes: true, with_subscription: true
566
+ end
567
+ end
568
+ end
569
+ end
570
+ ```
571
+
572
+ Then *activity_notification* will use *[ActivityNotification::NotificationsApiWithDeviseController](/app/controllers/activity_notification/notifications_api_with_devise_controller.rb)* as a notifications controller. The controller actions automatically call *authenticate_user!* and the user will be restricted to access and operate own notifications only, not others'.
573
+
574
+ ##### Configuring Devise Token Auth
575
+
576
+ At first, you have to set up [Devise Token Auth configuration](https://devise-token-auth.gitbook.io/devise-token-auth/config). You also have to configure your target model like this:
577
+
578
+ ```ruby
579
+ class User < ActiveRecord::Base
580
+ devise :database_authenticatable, :confirmable
581
+ include DeviseTokenAuth::Concerns::User
582
+ acts_as_target
583
+ end
584
+ ```
585
+
586
+ ##### Using REST API backend with Devise Token Auth
587
+
588
+ To sign in and get *access-token* from Devise Token Auth, call *sign_in* API which you configured by *mount_devise_token_auth_for* method:
589
+
590
+ ```console
591
+ $ curl -X POST -H "Content-Type: application/json" -D - -d '{"email": "ichiro@example.com","password": "changeit"}' https://activity-notification-example.herokuapp.com/api/v2/auth/sign_in
592
+
593
+
594
+ HTTP/1.1 200 OK
595
+ ...
596
+ Content-Type: application/json; charset=utf-8
597
+ access-token: ZiDvw8vJGtbESy5Qpw32Kw
598
+ token-type: Bearer
599
+ client: W0NkGrTS88xeOx4VDOS-Xg
600
+ expiry: 1576387310
601
+ uid: ichiro@example.com
602
+ ...
603
+
604
+ {
605
+ "data": {
606
+ "id": 1,
607
+ "email": "ichiro@example.com",
608
+ "provider": "email",
609
+ "uid": "ichiro@example.com",
610
+ "name": "Ichiro"
611
+ }
612
+ }
613
+ ```
614
+
615
+ Then, call *activity_notification* API with returned *access-token*, *client* and *uid* as HTTP headers:
616
+
617
+ ```console
618
+ $ curl -X GET -H "Content-Type: application/json" -H "access-token: ZiDvw8vJGtbESy5Qpw32Kw" -H "client: W0NkGrTS88xeOx4VDOS-Xg" -H "uid: ichiro@example.com" -D - https://activity-notification-example.herokuapp.com/api/v2/notifications
619
+
620
+ HTTP/1.1 200 OK
621
+ ...
622
+
623
+ {
624
+ "count": 7,
625
+ "notifications": [
626
+ ...
627
+ ]
628
+ }
629
+ ```
630
+
631
+ Without valid *access-token*, API returns *401 Unauthorized*:
632
+
633
+ ```console
634
+ $ curl -X GET -H "Content-Type: application/json" -D - https://activity-notification-example.herokuapp.com/api/v2/notifications
635
+
636
+ HTTP/1.1 401 Unauthorized
637
+ ...
638
+
639
+ {
640
+ "errors": [
641
+ "You need to sign in or sign up before continuing."
642
+ ]
643
+ }
644
+ ```
645
+
646
+ When you request restricted resources of unauthorized targets, *activity_notification* API returns *403 Forbidden*:
647
+
648
+ ```console
649
+ $ curl -X GET -H "Content-Type: application/json" -H "access-token: ZiDvw8vJGtbESy5Qpw32Kw" -H "client: W0NkGrTS88xeOx4VDOS-Xg" -H "uid: ichiro@example.com" -D - https://activity-notification-example.herokuapp.com/api/v2/notifications/1
650
+
651
+ HTTP/1.1 403 Forbidden
652
+ ...
653
+
654
+ {
655
+ "gem": "activity_notification",
656
+ "error": {
657
+ "code": 403,
658
+ "message": "Forbidden because of invalid parameter",
659
+ "type": "Wrong target is specified"
660
+ }
661
+ }
662
+ ```
663
+
664
+ See [Devise Token Auth documents](https://devise-token-auth.gitbook.io/devise-token-auth/) for more details.
665
+
666
+
667
+ ### Push notification with Action Cable
668
+
669
+ *activity_notification* supports push notification with Action Cable by WebSocket.
670
+ *activity_notification* only provides Action Cable channels implementation, does not connections.
671
+ You can use default implementaion in Rails or your custom `ApplicationCable::Connection` for Action Cable connections.
672
+
673
+ #### Enabling broadcasting notifications to channels
674
+
675
+ Broadcasting notifications to Action Cable channels is provided as [optional notification targets implementation](#action-cable-channels-as-optional-target).
676
+ This optional targets is disabled as default. You can configure it to enable Action Cable broadcasting in initializer *activity_notification.rb*.
677
+
678
+ ```ruby
679
+ # Enable Action Cable broadcasting as HTML view
680
+ config.action_cable_enabled = true
681
+ # Enable Action Cable API broadcasting as formatted JSON
682
+ config.action_cable_api_enabled = true
683
+ ```
684
+
685
+ You can also configure them for each model by *acts_as roles* like these:
686
+
687
+ ```ruby
688
+ class User < ActiveRecord::Base
689
+ # Allow Action Cable broadcasting
690
+ acts_as_target action_cable_allowed: true
691
+ end
692
+ ```
693
+
694
+ ```ruby
695
+ class Comment < ActiveRecord::Base
696
+ belongs_to :article
697
+ belongs_to :user
698
+
699
+ acts_as_notifiable :users,
700
+ targets: ->(comment, key) {
701
+ ([comment.article.user] + comment.article.reload.commented_users.to_a - [comment.user]).uniq
702
+ },
703
+ # Allow Action Cable broadcasting as HTML view
704
+ action_cable_allowed: true,
705
+ # Enable Action Cable API broadcasting as formatted JSON
706
+ action_cable_api_allowed: true
707
+ end
708
+ ```
709
+
710
+ Then, *activity_notification* will broadcast configured notifications to target channels by *[ActivityNotification::OptionalTarget::ActionCableChannel](/lib/activity_notification/optional_targets/action_cable_channel.rb)* and/or *[ActivityNotification::OptionalTarget::ActionCableApiChannel](/lib/activity_notification/optional_targets/action_cable_api_channel.rb)* as optional targets.
711
+
712
+ #### Subscribing notifications from channels
713
+
714
+ *activity_notification* provides *[ActivityNotification::NotificationChannel](/app/channels/activity_notification/notification_channel.rb)* and *[ActivityNotification::NotificationApiChannel](/app/channels/activity_notification/notification_api_channel.rb)* to subscribe broadcasted notifications with Action Cable.
715
+
716
+ You can simply create subscriptions for the specified target in your view like this:
717
+
718
+ ```js
719
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/push.js/1.0.9/push.min.js"></script>
720
+ <script>
721
+ App.activity_notification = App.cable.subscriptions.create(
722
+ {
723
+ channel: "ActivityNotification::NotificationChannel",
724
+ target_type: "<%= @target.to_class_name %>", target_id: "<%= @target.id %>"
725
+ },
726
+ {
727
+ connected: function() {
728
+ // Connected
729
+ },
730
+ disconnected: function() {
731
+ // Disconnected
732
+ },
733
+ rejected: function() {
734
+ // Rejected
735
+ },
736
+ received: function(notification) {
737
+ // Display notification
738
+
739
+ // Push notificaion using Web Notification API by Push.js
740
+ Push.create('ActivityNotification', {
741
+ body: notification.text,
742
+ timeout: 5000,
743
+ onClick: function () {
744
+ location.href = notification.notifiable_path;
745
+ this.close();
746
+ }
747
+ });
748
+ }
749
+ }
750
+ );
751
+ </script>
752
+ ```
753
+
754
+ or create subscriptions in your single page application with API channels like this:
755
+
756
+ ```js
757
+ // Vue.js implementation with actioncable-vue
758
+ export default {
759
+ // ...
760
+ mounted () {
761
+ this.subscribeActionCable();
762
+ },
763
+ channels: {
764
+ 'ActivityNotification::NotificationApiChannel': {
765
+ connected() {
766
+ // Connected
767
+ },
768
+ disconnected() {
769
+ // Disconnected
770
+ },
771
+ rejected() {
772
+ // Rejected
773
+ },
774
+ received(data) {
775
+ this.notify(data);
776
+ }
777
+ }
778
+ },
779
+ methods: {
780
+ subscribeActionCable () {
781
+ this.$cable.subscribe({
782
+ channel: 'ActivityNotification::NotificationApiChannel',
783
+ target_type: this.target_type, target_id: this.target_id
784
+ });
785
+ },
786
+ notify (data) {
787
+ // Display notification
788
+
789
+ // Push notificaion using Web Notification API by Push.js
790
+ Push.create('ActivityNotification', {
791
+ body: data.notification.text,
792
+ timeout: 5000,
793
+ onClick: function () {
794
+ location.href = data.notification.notifiable_path;
795
+ this.close();
796
+ }
797
+ });
798
+ }
799
+ }
800
+ }
801
+ ```
802
+
803
+ Then, *activity_notification* will push desktop notification using Web Notification API.
804
+
805
+ #### Subscribing notifications with Devise authentication
806
+
807
+ To use Devise integration, enable subscribing notifications with Devise authentication in initializer *activity_notification.rb*.
808
+
809
+ ```ruby
810
+ config.action_cable_with_devise = true
811
+ ```
812
+
813
+ You can also configure them for each target model by *acts_as_target* like this:
814
+
815
+ ```ruby
816
+ class User < ActiveRecord::Base
817
+ acts_as_target action_cable_allowed: true,
818
+ # Allow Action Cable broadcasting and enable subscribing notifications with Devise authentication
819
+ action_cable_with_devise: true
820
+ end
821
+ ```
822
+
823
+ When you set *action_cable_with_devise* option to *true*, *ActivityNotification::NotificationChannel* will reject your subscription requests for the target type.
824
+
825
+ *activity_notification* also provides *[ActivityNotification::NotificationWithDeviseChannel](/app/channels/activity_notification/notification_with_devise_channel.rb)* to create subscriptions integrated with Devise authentication.
826
+ You can simply use *ActivityNotification::NotificationWithDeviseChannel* instead of *ActivityNotification::NotificationChannel*:
827
+
828
+ ```js
829
+ App.activity_notification = App.cable.subscriptions.create(
830
+ {
831
+ channel: "ActivityNotification::NotificationWithDeviseChannel",
832
+ target_type: "<%= @target.to_class_name %>", target_id: "<%= @target.id %>"
833
+ },
834
+ {
835
+ // ...
836
+ }
837
+ );
838
+ ```
839
+
840
+ You can also create these subscriptions with *devise_type* parameter instead of *target_id* parameter like this:
841
+
842
+ ```js
843
+ App.activity_notification = App.cable.subscriptions.create(
844
+ {
845
+ channel: "ActivityNotification::NotificationWithDeviseChannel",
846
+ target_type: "users", devise_type: "users"
847
+ },
848
+ {
849
+ // ...
850
+ }
851
+ );
852
+ ```
853
+
854
+ *ActivityNotification::NotificationWithDeviseChannel* will confirm subscription requests from authenticated cookies by Devise. If the user has not signed in, the subscription request will be rejected. If the user has signed in as unauthorized user, the subscription request will be also rejected.
855
+
856
+ In addtion, you can use `Target#notification_action_cable_channel_class_name` method to select channel class depending on your *action_cable_with_devise* configuration for the target.
857
+
858
+ ```js
859
+ App.activity_notification = App.cable.subscriptions.create(
860
+ {
861
+ channel: "<%= @target.notification_action_cable_channel_class_name %>",
862
+ target_type: "<%= @target.to_class_name %>", target_id: "<%= @target.id %>"
863
+ },
864
+ {
865
+ // ...
866
+ }
867
+ );
868
+ ```
869
+
870
+ This script is also implemented in [default notifications index view](/app/views/activity_notification/notifications/default/index.html.erb) of *activity_notification*.
871
+
872
+ #### Subscribing notifications API with Devise Token Auth
873
+
874
+ To use Devise Token Auth integration, also enable subscribing notifications with Devise authentication in initializer *activity_notification.rb*.
875
+
876
+ ```ruby
877
+ config.action_cable_with_devise = true
878
+ ```
879
+
880
+ You can also configure them for each target model by *acts_as_target* like this:
881
+
882
+ ```ruby
883
+ class User < ActiveRecord::Base
884
+ acts_as_target action_cable_api_allowed: true,
885
+ # Allow Action Cable broadcasting and enable subscribing notifications API with Devise Token Auth
886
+ action_cable_with_devise: true
887
+ end
888
+ ```
889
+
890
+ When you set *action_cable_with_devise* option to *true*, *ActivityNotification::NotificationApiChannel* will reject your subscription requests for the target type.
891
+
892
+ *activity_notification* also provides *[ActivityNotification::NotificationApiWithDeviseChannel](/app/channels/activity_notification/notification_api_with_devise_channel.rb)* to create subscriptions integrated with Devise Token Auth.
893
+ You can simply use *ActivityNotification::NotificationApiWithDeviseChannel* instead of *ActivityNotification::NotificationApiChannel*. Note that you have to pass authenticated token by Devise Token Auth in subscription requests like this:
894
+
895
+ ```js
896
+ export default {
897
+ // ...
898
+ channels: {
899
+ 'ActivityNotification::NotificationApiWithDeviseChannel': {
900
+ // ...
901
+ }
902
+ },
903
+ methods: {
904
+ subscribeActionCable () {
905
+ this.$cable.subscribe({
906
+ channel: 'ActivityNotification::NotificationApiWithDeviseChannel',
907
+ target_type: this.target_type, target_id: this.target_id,
908
+ 'access-token': this.authHeaders['access-token'],
909
+ 'client': this.authHeaders['client'],
910
+ 'uid': this.authHeaders['uid']
911
+ });
912
+ }
913
+ }
914
+ }
915
+ ```
916
+
917
+ You can also create these subscriptions with *devise_type* parameter instead of *target_id* parameter like this:
918
+
919
+ ```js
920
+ export default {
921
+ // ...
922
+ methods: {
923
+ subscribeActionCable () {
924
+ this.$cable.subscribe({
925
+ channel: 'ActivityNotification::NotificationApiWithDeviseChannel',
926
+ target_type: "users", devise_type: "users",
927
+ 'access-token': this.authHeaders['access-token'],
928
+ 'client': this.authHeaders['client'],
929
+ 'uid': this.authHeaders['uid']
930
+ });
931
+ }
932
+ }
933
+ }
934
+ ```
935
+
936
+ *ActivityNotification::NotificationWithDeviseChannel* will confirm subscription requests from authenticated token by Devise Token Auth. If the token is invalid, the subscription request will be rejected. If the token of unauthorized user is passed, the subscription request will be also rejected.
937
+
938
+ This script is also implemented in [notifications index in sample single page application](/spec/rails_app/app/javascript/components/notifications/Index.vue).
939
+
940
+ #### Subscription management of Action Cable channels
941
+ Since broadcasting notifications to Action Cable channels is provided as [optional notification targets implementation](#action-cable-channels-as-optional-target), you can manage subscriptions as *:action_cable_channel* and *:action_cable_api_channel* optional target. See [subscription management of optional targets](#subscription-management-of-optional-targets) for more details.
942
+
943
+
944
+ ### Optional notification targets
945
+
946
+ *activity_notification* supports configurable optional notification targets like Amazon SNS, Slack, SMS and so on.
947
+
948
+ #### Configuring optional targets
949
+
950
+ *activity_notification* provides default optional target implementation for Amazon SNS and Slack.
951
+ You can develop any optional target classes which extends *ActivityNotification::OptionalTarget::Base*, and configure them to notifiable model by *acts_as_notifiable* like this:
952
+
953
+ ```ruby
954
+ class Comment < ActiveRecord::Base
955
+ belongs_to :article
956
+ belongs_to :user
957
+
958
+ require 'activity_notification/optional_targets/amazon_sns'
959
+ require 'activity_notification/optional_targets/slack'
960
+ require 'custom_optional_targets/console_output'
961
+ acts_as_notifiable :admins, targets: [Admin.first].compact,
962
+ notifiable_path: :article_notifiable_path,
963
+ # Set optional target implementation class and initializing parameters
964
+ optional_targets: {
965
+ ActivityNotification::OptionalTarget::AmazonSNS => { topic_arn: 'arn:aws:sns:XXXXX:XXXXXXXXXXXX:XXXXX' },
966
+ ActivityNotification::OptionalTarget::Slack => {
967
+ webhook_url: 'https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX',
968
+ slack_name: :slack_name, channel: 'activity_notification', username: 'ActivityNotification', icon_emoji: ":ghost:"
969
+ },
970
+ CustomOptionalTarget::ConsoleOutput => {}
971
+ }
972
+
973
+ def article_notifiable_path
974
+ article_path(article)
975
+ end
976
+ end
977
+ ```
978
+
979
+ Write *require* statement for optional target implementation classes and set them with initializing parameters to *acts_as_notifiable*.
980
+ *activity_notification* will publish all notifications of those targets and notifiables to optional targets.
981
+
982
+ #### Customizing message format
983
+
984
+ Optional targets prepare publishing messages from notification instance using view template like rendering notifications.
985
+ As default, all optional targets use *app/views/activity_notification/optional_targets/default/base/_default.text.erb*.
986
+ You can customize this template by creating *app/views/activity_notification/optional_targets/<target_class_name>/<optional_target_class_name>/<notification_key>.text.(|erb|haml|slim|something_else)*.
987
+ For example, if you have a notification for *:users* target with *:key* set to *"notification.comment.reply"* and *ActivityNotification::OptionalTarget::AmazonSNS* optional target is configured, the gem will look for a partial in *app/views/activity_notification/optional_targets/users/amazon_sns/comment/_reply.text.erb*.
988
+ The gem will also look for templates whose *<target_class_name>* is *default*, *<optional_target_class_name>* is *base* and *<notification_key>* is *default*, which means *app/views/activity_notification/optional_targets/users/amazon_sns/_default.text.erb*, *app/views/activity_notification/optional_targets/users/base/_default.text.erb*, *app/views/activity_notification/optional_targets/default/amazon_sns/_default.text.erb* and *app/views/activity_notification/optional_targets/default/base/_default.text.erb*.
989
+
990
+ #### Action Cable channels as optional target
991
+
992
+ *activity_notification* provides **ActivityNotification::OptionalTarget::ActionCableChannel** and **ActivityNotification::OptionalTarget::ActionCableApiChannel** as default optional target implementation to broadcast notifications to Action Cable channels.
993
+
994
+ Simply write `require 'activity_notification/optional_targets/action_cable_channel'` or `require 'activity_notification/optional_targets/action_cable_api_channel'` statement in your notifiable model and set *ActivityNotification::OptionalTarget::ActionCableChannel* or *ActivityNotification::OptionalTarget::ActionCableApiChannel* to *acts_as_notifiable* with initializing parameters. If you don't specify initializing parameters *ActivityNotification::OptionalTarget::ActionCableChannel* and *ActivityNotification::OptionalTarget::ActionCableApiChannel* uses configuration in *ActivityNotification.config*.
995
+
996
+ ```ruby
997
+ # Set Action Cable broadcasting as HTML view using optional target
998
+ class Comment < ActiveRecord::Base
999
+ require 'activity_notification/optional_targets/action_cable_channel'
1000
+ acts_as_notifiable :admins, targets: [Admin.first].compact,
1001
+ optional_targets: {
1002
+ ActivityNotification::OptionalTarget::ActionCableChannel => { channel_prefix: 'admin_notification' }
1003
+ }
1004
+ end
1005
+ ```
1006
+
1007
+ ```ruby
1008
+ # Set Action Cable API broadcasting as formatted JSON using optional target
1009
+ class Comment < ActiveRecord::Base
1010
+ require 'activity_notification/optional_targets/action_cable_api_channel'
1011
+ acts_as_notifiable :admins, targets: [Admin.first].compact,
1012
+ optional_targets: {
1013
+ ActivityNotification::OptionalTarget::ActionCableApiChannel => { channel_prefix: 'admin_notification_api' }
1014
+ }
1015
+ end
1016
+ ```
1017
+
1018
+ #### Amazon SNS as optional target
1019
+
1020
+ *activity_notification* provides **ActivityNotification::OptionalTarget::AmazonSNS** as default optional target implementation for Amazon SNS.
1021
+
1022
+ First, add **aws-sdk** or **aws-sdk-sns** (>= AWS SDK for Ruby v3) gem to your Gemfile and set AWS Credentials for SDK (See [Configuring the AWS SDK for Ruby](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html)).
1023
+
1024
+ ```ruby
1025
+ gem 'aws-sdk', '~> 2'
1026
+ # --- or ---
1027
+ gem 'aws-sdk-sns', '~> 1'
1028
+ ```
1029
+
1030
+ ```ruby
1031
+ require 'aws-sdk'
1032
+ # --- or ---
1033
+ require 'aws-sdk-sns'
1034
+
1035
+ Aws.config.update(
1036
+ region: 'your_region',
1037
+ credentials: Aws::Credentials.new('your_access_key_id', 'your_secret_access_key')
1038
+ )
1039
+ ```
1040
+
1041
+ Then, write `require 'activity_notification/optional_targets/amazon_sns'` statement in your notifiable model and set *ActivityNotification::OptionalTarget::AmazonSNS* to *acts_as_notifiable* with *:topic_arn*, *:target_arn* or *:phone_number* initializing parameters.
1042
+ Any other options for `Aws::SNS::Client.new` are available as initializing parameters. See [API Reference of Class: Aws::SNS::Client](http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SNS/Client.html) for more details.
1043
+
1044
+ ```ruby
1045
+ class Comment < ActiveRecord::Base
1046
+ require 'activity_notification/optional_targets/amazon_sns'
1047
+ acts_as_notifiable :admins, targets: [Admin.first].compact,
1048
+ optional_targets: {
1049
+ ActivityNotification::OptionalTarget::AmazonSNS => { topic_arn: 'arn:aws:sns:XXXXX:XXXXXXXXXXXX:XXXXX' }
1050
+ }
1051
+ end
1052
+ ```
1053
+
1054
+ #### Slack as optional target
1055
+
1056
+ *activity_notification* provides **ActivityNotification::OptionalTarget::Slack** as default optional target implementation for Slack.
1057
+
1058
+ First, add **slack-notifier** gem to your Gemfile and create Incoming WebHooks in Slack (See [Incoming WebHooks](https://wemakejp.slack.com/apps/A0F7XDUAZ-incoming-webhooks)).
1059
+
1060
+ ```ruby
1061
+ gem 'slack-notifier'
1062
+ ```
1063
+
1064
+ Then, write `require 'activity_notification/optional_targets/slack'` statement in your notifiable model and set *ActivityNotification::OptionalTarget::Slack* to *acts_as_notifiable* with *:webhook_url* and *:target_username* initializing parameters. *:webhook_url* is created WebHook URL and required, *:target_username* is target's slack user name as String value, symbol method name or lambda function and is optional.
1065
+ Any other options for `Slack::Notifier.new` are available as initializing parameters. See [Github slack-notifier](https://github.com/stevenosloan/slack-notifier) and [API Reference of Class: Slack::Notifier](http://www.rubydoc.info/gems/slack-notifier/1.5.1/Slack/Notifier) for more details.
1066
+
1067
+ ```ruby
1068
+ class Comment < ActiveRecord::Base
1069
+ require 'activity_notification/optional_targets/slack'
1070
+ acts_as_notifiable :admins, targets: [Admin.first].compact,
1071
+ optional_targets: {
1072
+ ActivityNotification::OptionalTarget::Slack => {
1073
+ webhook_url: 'https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX',
1074
+ target_username: :slack_username, channel: 'activity_notification', username: 'ActivityNotification', icon_emoji: ":ghost:"
1075
+ }
1076
+ }
1077
+ end
1078
+ ```
1079
+
1080
+ #### Developing custom optional targets
1081
+
1082
+ You can develop any custom optional targets.
1083
+ Custom optional target class must extend **ActivityNotification::OptionalTarget::Base** and override **initialize_target** and **notify** method.
1084
+ You can use **render_notification_message** method to prepare message from notification instance using view template.
1085
+
1086
+ For example, create *lib/custom_optional_targets/amazon_sns.rb* as follows:
1087
+
1088
+ ```ruby
1089
+ module CustomOptionalTarget
1090
+ # Custom optional target implementation for mobile push notification or SMS using Amazon SNS.
1091
+ class AmazonSNS < ActivityNotification::OptionalTarget::Base
1092
+ require 'aws-sdk'
1093
+
1094
+ # Initialize method to prepare Aws::SNS::Client
1095
+ def initialize_target(options = {})
1096
+ @topic_arn = options.delete(:topic_arn)
1097
+ @target_arn = options.delete(:target_arn)
1098
+ @phone_number = options.delete(:phone_number)
1099
+ @sns_client = Aws::SNS::Client.new(options)
1100
+ end
1101
+
1102
+ # Publishes notification message to Amazon SNS
1103
+ def notify(notification, options = {})
1104
+ @sns_client.publish(
1105
+ topic_arn: notification.target.resolve_value(options.delete(:topic_arn) || @topic_arn),
1106
+ target_arn: notification.target.resolve_value(options.delete(:target_arn) || @target_arn),
1107
+ phone_number: notification.target.resolve_value(options.delete(:phone_number) || @phone_number),
1108
+ message: render_notification_message(notification, options)
1109
+ )
1110
+ end
1111
+ end
1112
+ end
1113
+ ```
1114
+
1115
+ Then, you can configure them to notifiable model by *acts_as_notifiable* like this:
1116
+
1117
+ ```ruby
1118
+ class Comment < ActiveRecord::Base
1119
+ require 'custom_optional_targets/amazon_sns'
1120
+ acts_as_notifiable :admins, targets: [Admin.first].compact,
1121
+ optional_targets: {
1122
+ CustomOptionalTarget::AmazonSNS => { topic_arn: 'arn:aws:sns:XXXXX:XXXXXXXXXXXX:XXXXX' }
1123
+ }
1124
+ end
1125
+ ```
1126
+
1127
+ *acts_as_notifiable* creates optional target instances and calls *initialize_target* method with initializing parameters.
1128
+
1129
+ #### Subscription management of optional targets
1130
+
1131
+ *ActivityNotification::Subscription* model provides API to subscribe and unsubscribe optional notification targets. Call these methods with optional target name like this:
1132
+
1133
+ ```ruby
1134
+ # Subscribe Acltion Cable channel for 'comment.reply' notifications
1135
+ user.find_or_create_subscription('comment.reply').subscribe_to_optional_target(:action_cable_channel)
1136
+
1137
+ # Subscribe Acltion Cable API channel for 'comment.reply' notifications
1138
+ user.find_or_create_subscription('comment.reply').subscribe_to_optional_target(:action_cable_api_channel)
1139
+
1140
+ # Unsubscribe Slack notification for 'comment.reply' notifications
1141
+ user.find_or_create_subscription('comment.reply').unsubscribe_to_optional_target(:slack)
1142
+ ```
1143
+
1144
+ You can also manage subscriptions of optional targets by subscriptions REST API. See [REST API backend](#rest-api-backend) for more details.
1145
+
1146
+ You can see sample subscription management view in demo application here: *https://activity-notification-example.herokuapp.com/users/1/subscriptions*