activity_notification 1.4.4 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +22 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  4. data/.github/pull_request_template.md +13 -0
  5. data/.github/workflows/build.yml +116 -0
  6. data/.gitignore +15 -3
  7. data/CHANGELOG.md +200 -1
  8. data/Gemfile +17 -2
  9. data/Procfile +2 -0
  10. data/README.md +168 -1033
  11. data/Rakefile +19 -10
  12. data/activity_notification.gemspec +14 -9
  13. data/app/channels/activity_notification/notification_api_channel.rb +12 -0
  14. data/app/channels/activity_notification/notification_api_with_devise_channel.rb +46 -0
  15. data/app/channels/activity_notification/notification_channel.rb +37 -0
  16. data/app/channels/activity_notification/notification_with_devise_channel.rb +51 -0
  17. data/app/controllers/activity_notification/apidocs_controller.rb +75 -0
  18. data/app/controllers/activity_notification/notifications_api_controller.rb +143 -0
  19. data/app/controllers/activity_notification/notifications_api_with_devise_controller.rb +7 -0
  20. data/app/controllers/activity_notification/notifications_controller.rb +60 -54
  21. data/app/controllers/activity_notification/subscriptions_api_controller.rb +197 -0
  22. data/app/controllers/activity_notification/subscriptions_api_with_devise_controller.rb +7 -0
  23. data/app/controllers/activity_notification/subscriptions_controller.rb +83 -73
  24. data/app/jobs/activity_notification/notify_all_job.rb +25 -0
  25. data/app/jobs/activity_notification/notify_job.rb +26 -0
  26. data/app/jobs/activity_notification/notify_to_job.rb +25 -0
  27. data/app/views/activity_notification/notifications/default/_default.html.erb +23 -23
  28. data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +19 -19
  29. data/app/views/activity_notification/notifications/default/_index.html.erb +3 -3
  30. data/app/views/activity_notification/notifications/default/index.html.erb +60 -7
  31. data/app/views/activity_notification/notifications/default/open.js.erb +2 -2
  32. data/app/views/activity_notification/notifications/default/open_all.js.erb +2 -2
  33. data/app/views/activity_notification/notifications/default/show.html.erb +2 -2
  34. data/app/views/activity_notification/optional_targets/default/action_cable_channel/_default.html.erb +176 -0
  35. data/app/views/activity_notification/optional_targets/default/base/_default.text.erb +1 -1
  36. data/app/views/activity_notification/optional_targets/default/slack/_default.text.erb +1 -1
  37. data/app/views/activity_notification/subscriptions/default/_form.html.erb +2 -2
  38. data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +5 -33
  39. data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +8 -8
  40. data/app/views/activity_notification/subscriptions/default/index.html.erb +13 -9
  41. data/app/views/activity_notification/subscriptions/default/show.html.erb +3 -3
  42. data/app/views/activity_notification/subscriptions/default/subscribe.js.erb +1 -1
  43. data/app/views/activity_notification/subscriptions/default/subscribe_to_email.js.erb +1 -1
  44. data/app/views/activity_notification/subscriptions/default/subscribe_to_optional_target.js.erb +1 -1
  45. data/app/views/activity_notification/subscriptions/default/unsubscribe.js.erb +1 -1
  46. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_email.js.erb +1 -1
  47. data/app/views/activity_notification/subscriptions/default/unsubscribe_to_optional_target.js.erb +1 -1
  48. data/bin/_dynamodblocal +4 -0
  49. data/bin/bundle_update.sh +7 -0
  50. data/bin/deploy_on_heroku.sh +16 -0
  51. data/bin/install_dynamodblocal.sh +5 -0
  52. data/bin/start_dynamodblocal.sh +47 -0
  53. data/bin/stop_dynamodblocal.sh +34 -0
  54. data/docs/CODE_OF_CONDUCT.md +76 -0
  55. data/docs/CONTRIBUTING.md +36 -0
  56. data/docs/Functions.md +1146 -0
  57. data/docs/Setup.md +817 -0
  58. data/docs/Testing.md +148 -0
  59. data/gemfiles/Gemfile.rails-5.0 +8 -1
  60. data/gemfiles/Gemfile.rails-5.1 +7 -1
  61. data/gemfiles/Gemfile.rails-5.2 +24 -0
  62. data/gemfiles/Gemfile.rails-6.0 +23 -0
  63. data/gemfiles/Gemfile.rails-6.1 +22 -0
  64. data/gemfiles/Gemfile.rails-7.0 +25 -0
  65. data/lib/activity_notification/apis/notification_api.rb +356 -159
  66. data/lib/activity_notification/apis/subscription_api.rb +98 -59
  67. data/lib/activity_notification/apis/swagger.rb +6 -0
  68. data/lib/activity_notification/common.rb +18 -7
  69. data/lib/activity_notification/config.rb +176 -30
  70. data/lib/activity_notification/controllers/common_api_controller.rb +30 -0
  71. data/lib/activity_notification/controllers/common_controller.rb +47 -27
  72. data/lib/activity_notification/controllers/concerns/swagger/error_responses.rb +55 -0
  73. data/lib/activity_notification/controllers/concerns/swagger/notifications_api.rb +273 -0
  74. data/lib/activity_notification/controllers/concerns/swagger/notifications_parameters.rb +92 -0
  75. data/lib/activity_notification/controllers/concerns/swagger/subscriptions_api.rb +405 -0
  76. data/lib/activity_notification/controllers/concerns/swagger/subscriptions_parameters.rb +50 -0
  77. data/lib/activity_notification/controllers/devise_authentication_controller.rb +22 -5
  78. data/lib/activity_notification/gem_version.rb +14 -0
  79. data/lib/activity_notification/helpers/errors.rb +6 -0
  80. data/lib/activity_notification/helpers/view_helpers.rb +118 -28
  81. data/lib/activity_notification/mailers/helpers.rb +19 -12
  82. data/lib/activity_notification/models/concerns/notifiable.rb +142 -55
  83. data/lib/activity_notification/models/concerns/subscriber.rb +28 -13
  84. data/lib/activity_notification/models/concerns/swagger/error_schema.rb +36 -0
  85. data/lib/activity_notification/models/concerns/swagger/notification_schema.rb +209 -0
  86. data/lib/activity_notification/models/concerns/swagger/subscription_schema.rb +162 -0
  87. data/lib/activity_notification/models/concerns/target.rb +131 -32
  88. data/lib/activity_notification/models/notification.rb +1 -0
  89. data/lib/activity_notification/models/subscription.rb +1 -0
  90. data/lib/activity_notification/models.rb +23 -1
  91. data/lib/activity_notification/optional_targets/action_cable_api_channel.rb +69 -0
  92. data/lib/activity_notification/optional_targets/action_cable_channel.rb +68 -0
  93. data/lib/activity_notification/optional_targets/base.rb +9 -15
  94. data/lib/activity_notification/orm/active_record/notification.rb +23 -34
  95. data/lib/activity_notification/orm/active_record/subscription.rb +1 -1
  96. data/lib/activity_notification/orm/active_record.rb +1 -1
  97. data/lib/activity_notification/orm/dynamoid/extension.rb +262 -0
  98. data/lib/activity_notification/orm/dynamoid/notification.rb +224 -0
  99. data/lib/activity_notification/orm/dynamoid/subscription.rb +82 -0
  100. data/lib/activity_notification/orm/dynamoid.rb +530 -0
  101. data/lib/activity_notification/orm/mongoid/notification.rb +29 -28
  102. data/lib/activity_notification/orm/mongoid/subscription.rb +3 -3
  103. data/lib/activity_notification/orm/mongoid.rb +33 -1
  104. data/lib/activity_notification/rails/routes.rb +273 -60
  105. data/lib/activity_notification/renderable.rb +22 -7
  106. data/lib/activity_notification/roles/acts_as_notifiable.rb +64 -1
  107. data/lib/activity_notification/roles/acts_as_target.rb +99 -9
  108. data/lib/activity_notification/version.rb +1 -1
  109. data/lib/activity_notification.rb +14 -0
  110. data/lib/generators/activity_notification/controllers_generator.rb +2 -1
  111. data/lib/generators/templates/activity_notification.rb +61 -7
  112. data/lib/generators/templates/controllers/README +2 -2
  113. data/lib/generators/templates/controllers/notifications_api_controller.rb +31 -0
  114. data/lib/generators/templates/controllers/notifications_api_with_devise_controller.rb +31 -0
  115. data/lib/generators/templates/controllers/notifications_controller.rb +1 -37
  116. data/lib/generators/templates/controllers/notifications_with_devise_controller.rb +1 -45
  117. data/lib/generators/templates/controllers/subscriptions_api_controller.rb +61 -0
  118. data/lib/generators/templates/controllers/subscriptions_api_with_devise_controller.rb +61 -0
  119. data/lib/generators/templates/controllers/subscriptions_controller.rb +14 -37
  120. data/lib/generators/templates/controllers/subscriptions_with_devise_controller.rb +14 -45
  121. data/lib/generators/templates/migrations/migration.rb +5 -5
  122. data/lib/generators/templates/models/README +8 -4
  123. data/lib/generators/templates/models/notification.rb +1 -1
  124. data/lib/generators/templates/models/subscription.rb +1 -1
  125. data/lib/tasks/activity_notification_tasks.rake +14 -4
  126. data/package.json +8 -0
  127. data/spec/channels/notification_api_channel_shared_examples.rb +59 -0
  128. data/spec/channels/notification_api_channel_spec.rb +49 -0
  129. data/spec/channels/notification_api_with_devise_channel_spec.rb +76 -0
  130. data/spec/channels/notification_channel_shared_examples.rb +59 -0
  131. data/spec/channels/notification_channel_spec.rb +48 -0
  132. data/spec/channels/notification_with_devise_channel_spec.rb +97 -0
  133. data/spec/concerns/apis/notification_api_spec.rb +177 -12
  134. data/spec/concerns/apis/subscription_api_spec.rb +146 -4
  135. data/spec/concerns/common_spec.rb +25 -3
  136. data/spec/concerns/models/notifiable_spec.rb +161 -11
  137. data/spec/concerns/models/subscriber_spec.rb +253 -79
  138. data/spec/concerns/models/target_spec.rb +180 -47
  139. data/spec/concerns/renderable_spec.rb +35 -16
  140. data/spec/config_spec.rb +52 -1
  141. data/spec/controllers/controller_spec_utility.rb +100 -0
  142. data/spec/controllers/notifications_api_controller_shared_examples.rb +506 -0
  143. data/spec/controllers/notifications_api_controller_spec.rb +19 -0
  144. data/spec/controllers/notifications_api_with_devise_controller_spec.rb +60 -0
  145. data/spec/controllers/notifications_controller_shared_examples.rb +55 -76
  146. data/spec/controllers/notifications_controller_spec.rb +1 -2
  147. data/spec/controllers/notifications_with_devise_controller_spec.rb +14 -8
  148. data/spec/controllers/subscriptions_api_controller_shared_examples.rb +750 -0
  149. data/spec/controllers/subscriptions_api_controller_spec.rb +19 -0
  150. data/spec/controllers/subscriptions_api_with_devise_controller_spec.rb +60 -0
  151. data/spec/controllers/subscriptions_controller_shared_examples.rb +99 -121
  152. data/spec/controllers/subscriptions_controller_spec.rb +1 -2
  153. data/spec/controllers/subscriptions_with_devise_controller_spec.rb +14 -8
  154. data/spec/factories/notifications.rb +1 -1
  155. data/spec/factories/subscriptions.rb +3 -3
  156. data/spec/factories/users.rb +3 -3
  157. data/spec/generators/migration/migration_generator_spec.rb +29 -4
  158. data/spec/helpers/view_helpers_spec.rb +31 -21
  159. data/spec/jobs/notify_all_job_spec.rb +23 -0
  160. data/spec/jobs/notify_job_spec.rb +23 -0
  161. data/spec/jobs/notify_to_job_spec.rb +23 -0
  162. data/spec/mailers/mailer_spec.rb +42 -1
  163. data/spec/models/dummy/dummy_group_spec.rb +4 -0
  164. data/spec/models/dummy/dummy_notifiable_spec.rb +4 -0
  165. data/spec/models/dummy/dummy_notifier_spec.rb +4 -0
  166. data/spec/models/dummy/dummy_subscriber_spec.rb +3 -0
  167. data/spec/models/dummy/dummy_target_spec.rb +4 -0
  168. data/spec/models/notification_spec.rb +181 -45
  169. data/spec/models/subscription_spec.rb +77 -27
  170. data/spec/optional_targets/action_cable_api_channel_spec.rb +34 -0
  171. data/spec/optional_targets/action_cable_channel_spec.rb +41 -0
  172. data/spec/optional_targets/amazon_sns_spec.rb +0 -2
  173. data/spec/optional_targets/slack_spec.rb +0 -2
  174. data/spec/orm/dynamoid_spec.rb +115 -0
  175. data/spec/rails_app/Rakefile +9 -0
  176. data/spec/rails_app/app/assets/config/manifest.js +3 -0
  177. data/spec/rails_app/app/assets/javascripts/application.js +2 -1
  178. data/spec/rails_app/app/assets/javascripts/cable.js +12 -0
  179. data/spec/rails_app/app/controllers/admins_controller.rb +21 -0
  180. data/spec/rails_app/app/controllers/application_controller.rb +1 -1
  181. data/spec/rails_app/app/controllers/articles_controller.rb +6 -1
  182. data/spec/rails_app/app/controllers/comments_controller.rb +3 -1
  183. data/spec/rails_app/app/controllers/spa_controller.rb +7 -0
  184. data/spec/rails_app/app/controllers/users/notifications_controller.rb +0 -65
  185. data/spec/rails_app/app/controllers/users/notifications_with_devise_controller.rb +0 -73
  186. data/spec/rails_app/app/controllers/users/subscriptions_controller.rb +0 -77
  187. data/spec/rails_app/app/controllers/users/subscriptions_with_devise_controller.rb +0 -85
  188. data/spec/rails_app/app/controllers/users_controller.rb +26 -0
  189. data/spec/rails_app/app/javascript/App.vue +40 -0
  190. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +82 -0
  191. data/spec/rails_app/app/javascript/components/Top.vue +98 -0
  192. data/spec/rails_app/app/javascript/components/notifications/Index.vue +200 -0
  193. data/spec/rails_app/app/javascript/components/notifications/Notification.vue +133 -0
  194. data/spec/rails_app/app/javascript/components/notifications/NotificationContent.vue +122 -0
  195. data/spec/rails_app/app/javascript/components/subscriptions/Index.vue +279 -0
  196. data/spec/rails_app/app/javascript/components/subscriptions/NewSubscription.vue +112 -0
  197. data/spec/rails_app/app/javascript/components/subscriptions/NotificationKey.vue +141 -0
  198. data/spec/rails_app/app/javascript/components/subscriptions/Subscription.vue +226 -0
  199. data/spec/rails_app/app/javascript/config/development.js +5 -0
  200. data/spec/rails_app/app/javascript/config/environment.js +7 -0
  201. data/spec/rails_app/app/javascript/config/production.js +5 -0
  202. data/spec/rails_app/app/javascript/config/test.js +5 -0
  203. data/spec/rails_app/app/javascript/packs/application.js +18 -0
  204. data/spec/rails_app/app/javascript/packs/spa.js +14 -0
  205. data/spec/rails_app/app/javascript/router/index.js +73 -0
  206. data/spec/rails_app/app/javascript/store/index.js +37 -0
  207. data/spec/rails_app/app/models/admin.rb +15 -10
  208. data/spec/rails_app/app/models/article.rb +25 -20
  209. data/spec/rails_app/app/models/comment.rb +27 -62
  210. data/spec/rails_app/app/models/dummy/dummy_base.rb +1 -0
  211. data/spec/rails_app/app/models/dummy/dummy_group.rb +9 -0
  212. data/spec/rails_app/app/models/dummy/dummy_notifiable.rb +1 -0
  213. data/spec/rails_app/app/models/dummy/dummy_notifiable_target.rb +27 -0
  214. data/spec/rails_app/app/models/dummy/dummy_notifier.rb +1 -0
  215. data/spec/rails_app/app/models/dummy/dummy_subscriber.rb +1 -0
  216. data/spec/rails_app/app/models/dummy/dummy_target.rb +1 -0
  217. data/spec/rails_app/app/models/user.rb +44 -18
  218. data/spec/rails_app/app/views/activity_notification/notifications/default/article/_update.html.erb +146 -0
  219. data/spec/rails_app/app/views/activity_notification/notifications/users/overridden/custom/_test.html.erb +1 -0
  220. data/spec/rails_app/app/views/activity_notification/optional_targets/admins/amazon_sns/comment/_default.text.erb +1 -1
  221. data/spec/rails_app/app/views/articles/index.html.erb +68 -20
  222. data/spec/rails_app/app/views/articles/show.html.erb +1 -1
  223. data/spec/rails_app/app/views/layouts/_header.html.erb +9 -3
  224. data/spec/rails_app/app/views/spa/index.html.erb +2 -0
  225. data/spec/rails_app/babel.config.js +72 -0
  226. data/spec/rails_app/bin/webpack +18 -0
  227. data/spec/rails_app/bin/webpack-dev-server +18 -0
  228. data/spec/rails_app/config/application.rb +26 -6
  229. data/spec/rails_app/config/cable.yml +8 -0
  230. data/spec/rails_app/config/database.yml +1 -1
  231. data/spec/rails_app/config/dynamoid.rb +13 -0
  232. data/spec/rails_app/config/environment.rb +5 -1
  233. data/spec/rails_app/config/environments/development.rb +5 -0
  234. data/spec/rails_app/config/environments/production.rb +7 -1
  235. data/spec/rails_app/config/environments/test.rb +7 -11
  236. data/spec/rails_app/config/initializers/activity_notification.rb +63 -9
  237. data/spec/rails_app/config/initializers/copy_it.aws.rb.template +6 -0
  238. data/spec/rails_app/config/initializers/devise_token_auth.rb +55 -0
  239. data/spec/rails_app/config/initializers/mysql.rb +9 -0
  240. data/spec/rails_app/config/locales/activity_notification.en.yml +10 -4
  241. data/spec/rails_app/config/routes.rb +42 -1
  242. data/spec/rails_app/config/webpack/development.js +5 -0
  243. data/spec/rails_app/config/webpack/environment.js +7 -0
  244. data/spec/rails_app/config/webpack/loaders/vue.js +6 -0
  245. data/spec/rails_app/config/webpack/production.js +5 -0
  246. data/spec/rails_app/config/webpack/test.js +5 -0
  247. data/spec/rails_app/config/webpacker.yml +97 -0
  248. data/spec/rails_app/db/migrate/{20160715050433_create_test_tables.rb → 20160716000000_create_test_tables.rb} +1 -1
  249. data/spec/rails_app/db/migrate/{20160715050420_create_activity_notification_tables.rb → 20181209000000_create_activity_notification_tables.rb} +3 -3
  250. data/spec/rails_app/db/migrate/20191201000000_add_tokens_to_users.rb +10 -0
  251. data/spec/rails_app/db/schema.rb +46 -43
  252. data/spec/rails_app/db/seeds.rb +28 -4
  253. data/spec/rails_app/lib/custom_optional_targets/raise_error.rb +14 -0
  254. data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +14 -4
  255. data/spec/rails_app/package.json +23 -0
  256. data/spec/rails_app/postcss.config.js +12 -0
  257. data/spec/roles/acts_as_group_spec.rb +0 -2
  258. data/spec/roles/acts_as_notifiable_spec.rb +80 -20
  259. data/spec/roles/acts_as_notifier_spec.rb +0 -2
  260. data/spec/roles/acts_as_target_spec.rb +1 -5
  261. data/spec/spec_helper.rb +13 -11
  262. data/spec/version_spec.rb +31 -0
  263. metadata +306 -53
  264. data/.travis.yml +0 -85
  265. data/Gemfile.lock +0 -234
  266. data/gemfiles/Gemfile.rails-4.2 +0 -17
  267. data/gemfiles/Gemfile.rails-4.2.lock +0 -225
  268. data/gemfiles/Gemfile.rails-5.0.lock +0 -234
  269. data/gemfiles/Gemfile.rails-5.1.lock +0 -234
  270. data/spec/rails_app/app/views/activity_notification/notifications/users/overriden/custom/_test.html.erb +0 -1
  271. /data/spec/rails_app/app/{models → assets/images}/.keep +0 -0
@@ -0,0 +1,226 @@
1
+ <template>
2
+ <div class="fields_wrapper configured">
3
+ <div class="fields_title_wrapper">
4
+ <h3 class="fields_title">
5
+ {{ subscription.key }}
6
+ </h3>
7
+
8
+ <p>
9
+ <router-link v-bind:to="{ path : $route.path.replace('subscriptions', 'notifications') + '?filtered_by_key=' + subscription.key }">Notifications</router-link>
10
+ </p>
11
+ </div>
12
+
13
+ <div class="field_wrapper subscribing">
14
+ <div class="field_label">
15
+ <label>
16
+ Notification
17
+ </label>
18
+ </div>
19
+ <div class="field">
20
+ <div class="ui checkbox">
21
+ <div v-if="subscription.subscribing">
22
+ <a href="#" v-on:click="unsubscribe(subscription)" data-remote="true">
23
+ <input type="checkbox" checked="checked" />
24
+ <div class="slider" />
25
+ </a>
26
+ </div>
27
+ <div v-else>
28
+ <a href="#" v-on:click="subscribe(subscription)" data-remote="true">
29
+ <input type="checkbox" />
30
+ <div class="slider" />
31
+ </a>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+
37
+ <div v-bind:class="[subscription.subscribing ? '' : 'hidden', 'field_wrapper subscribing_to_email']">
38
+ <div class="field_label">
39
+ <label>
40
+ Email notification
41
+ </label>
42
+ </div>
43
+ <div class="field">
44
+ <div class="ui checkbox">
45
+ <div v-if="subscription.subscribing_to_email">
46
+ <a href="#" v-on:click="unsubscribe_to_email(subscription)" data-remote="true">
47
+ <label>
48
+ <input type="checkbox" checked="checked" />
49
+ <div class="slider" />
50
+ </label>
51
+ </a>
52
+ </div>
53
+ <div v-else>
54
+ <a href="#" v-on:click="subscribe_to_email(subscription)" data-remote="true">
55
+ <label>
56
+ <input type="checkbox" />
57
+ <div class="slider" />
58
+ </label>
59
+ </a>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ <div v-bind:class="[subscription.subscribing ? '' : 'hidden', 'field_wrapper subscribing_to_optional_targets']">
66
+ <div v-for="(optionalTargetSubscription, optionalTargetName) in subscription.optional_targets" :key="optionalTargetName">
67
+ <div class="field_label">
68
+ <label>
69
+ Optional tagret ({{ optionalTargetName }})
70
+ </label>
71
+ </div>
72
+ <div class="field">
73
+ <div class="ui checkbox">
74
+ <div v-if="optionalTargetSubscription.subscribing">
75
+ <a href="#" v-on:click="unsubscribe_to_optional_target(subscription, optionalTargetName)" data-remote="true">
76
+ <label>
77
+ <input type="checkbox" checked="checked" />
78
+ <div class="slider" />
79
+ </label>
80
+ </a>
81
+ </div>
82
+ <div v-else>
83
+ <a href="#" v-on:click="subscribe_to_optional_target(subscription, optionalTargetName)" data-remote="true">
84
+ <label>
85
+ <input type="checkbox" />
86
+ <div class="slider" />
87
+ </label>
88
+ </a>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="ui button">
96
+ <a href="#" v-on:click="destroy(subscription)" data-confirm="Are you sure?" class="button" data-remote="true">Destroy</a>
97
+ </div>
98
+ </div>
99
+ </template>
100
+
101
+ <script>
102
+ import axios from 'axios'
103
+
104
+ export default {
105
+ name: 'Subscription',
106
+ props: {
107
+ targetSubscription: {
108
+ type: Object,
109
+ required: true
110
+ },
111
+ targetApiPath: {
112
+ type: String,
113
+ required: true
114
+ }
115
+ },
116
+ data () {
117
+ return {
118
+ subscription: this.targetSubscription,
119
+ baseURL: axios.defaults.baseURL + this.targetApiPath
120
+ }
121
+ },
122
+ methods: {
123
+ subscribe (subscription) {
124
+ axios
125
+ .put(this.targetApiPath + '/subscriptions/' + subscription.id + '/subscribe')
126
+ .then(response => {
127
+ if (response.status == 200) {
128
+ this.subscription = response.data
129
+ }
130
+ })
131
+ .catch (error => {
132
+ if (error.response.status == 401) {
133
+ this.$router.push('/logout');
134
+ }
135
+ })
136
+ },
137
+ unsubscribe (subscription) {
138
+ axios
139
+ .put(this.targetApiPath + '/subscriptions/' + subscription.id + '/unsubscribe')
140
+ .then(response => {
141
+ if (response.status == 200) {
142
+ this.subscription = response.data
143
+ }
144
+ })
145
+ .catch (error => {
146
+ if (error.response.status == 401) {
147
+ this.$router.push('/logout');
148
+ }
149
+ })
150
+ },
151
+ subscribe_to_email (subscription) {
152
+ axios
153
+ .put(this.targetApiPath + '/subscriptions/' + subscription.id + '/subscribe_to_email')
154
+ .then(response => {
155
+ if (response.status == 200) {
156
+ this.subscription = response.data
157
+ }
158
+ })
159
+ .catch (error => {
160
+ if (error.response.status == 401) {
161
+ this.$router.push('/logout');
162
+ }
163
+ })
164
+ },
165
+ unsubscribe_to_email (subscription) {
166
+ axios
167
+ .put(this.targetApiPath + '/subscriptions/' + subscription.id + '/unsubscribe_to_email')
168
+ .then(response => {
169
+ if (response.status == 200) {
170
+ this.subscription = response.data
171
+ }
172
+ })
173
+ .catch (error => {
174
+ if (error.response.status == 401) {
175
+ this.$router.push('/logout');
176
+ }
177
+ })
178
+ },
179
+ subscribe_to_optional_target (subscription, optionalTargetName) {
180
+ axios
181
+ .put(this.targetApiPath + '/subscriptions/' + subscription.id + '/subscribe_to_optional_target?optional_target_name=' + optionalTargetName)
182
+ .then(response => {
183
+ if (response.status == 200) {
184
+ this.subscription = response.data
185
+ }
186
+ })
187
+ .catch (error => {
188
+ if (error.response.status == 401) {
189
+ this.$router.push('/logout');
190
+ }
191
+ })
192
+ },
193
+ unsubscribe_to_optional_target (subscription, optionalTargetName) {
194
+ axios
195
+ .put(this.targetApiPath + '/subscriptions/' + subscription.id + '/unsubscribe_to_optional_target?optional_target_name=' + optionalTargetName)
196
+ .then(response => {
197
+ if (response.status == 200) {
198
+ this.subscription = response.data
199
+ }
200
+ })
201
+ .catch (error => {
202
+ if (error.response.status == 401) {
203
+ this.$router.push('/logout');
204
+ }
205
+ })
206
+ },
207
+ destroy (subscription) {
208
+ axios
209
+ .delete(this.targetApiPath + '/subscriptions/' + subscription.id)
210
+ .then(response => {
211
+ if (response.status == 204) {
212
+ this.$emit('getSubscriptions');
213
+ }
214
+ })
215
+ .catch (error => {
216
+ if (error.response.status == 401) {
217
+ this.$router.push('/logout');
218
+ }
219
+ })
220
+ }
221
+ }
222
+ }
223
+ </script>
224
+
225
+ <style scoped>
226
+ </style>
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ ACTION_CABLE_CONNECTION_URL: 'ws://localhost:3000/cable'
3
+ }
4
+
5
+ module.exports = config;
@@ -0,0 +1,7 @@
1
+ const config = require('./' + process.env.NODE_ENV);
2
+
3
+ export default class Environment {
4
+ static get ACTION_CABLE_CONNECTION_URL() {
5
+ return config.ACTION_CABLE_CONNECTION_URL;
6
+ }
7
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ ACTION_CABLE_CONNECTION_URL: 'wss://activity-notification-example.herokuapp.com/cable'
3
+ }
4
+
5
+ module.exports = config;
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ ACTION_CABLE_CONNECTION_URL: 'ws://localhost:3000/cable'
3
+ }
4
+
5
+ module.exports = config;
@@ -0,0 +1,18 @@
1
+ /* eslint no-console:0 */
2
+ // This file is automatically compiled by Webpack, along with any other files
3
+ // present in this directory. You're encouraged to place your actual application logic in
4
+ // a relevant structure within app/javascript and only use these pack files to reference
5
+ // that code so it'll be compiled.
6
+ //
7
+ // To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
8
+ // layout file, like app/views/layouts/application.html.erb
9
+
10
+
11
+ // Uncomment to copy all static images under ../images to the output folder and reference
12
+ // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
13
+ // or the `imagePath` JavaScript helper below.
14
+ //
15
+ // const images = require.context('../images', true)
16
+ // const imagePath = (name) => images(name, true)
17
+
18
+ console.log('Hello World from Webpacker')
@@ -0,0 +1,14 @@
1
+ import Vue from 'vue'
2
+ import App from '../App.vue'
3
+ import router from '../router'
4
+ import store from '../store'
5
+
6
+ Vue.config.productionTip = false
7
+
8
+ document.addEventListener('DOMContentLoaded', () => {
9
+ new Vue({
10
+ router,
11
+ store,
12
+ render: h => h(App)
13
+ }).$mount('#spa')
14
+ })
@@ -0,0 +1,73 @@
1
+ import Vue from 'vue'
2
+ import VueRouter from 'vue-router'
3
+ import store from '../store'
4
+ import DeviseTokenAuth from '../components/DeviseTokenAuth.vue'
5
+ import Top from '../components/Top.vue'
6
+ import NotificationsIndex from '../components/notifications/Index.vue'
7
+ import SubscriptionsIndex from '../components/subscriptions/Index.vue'
8
+
9
+ Vue.use(VueRouter)
10
+
11
+ const routes = [
12
+ // Routes for common components
13
+ { path: '/', component: Top },
14
+ { path: '/login', component: DeviseTokenAuth },
15
+ { path: '/logout', component: DeviseTokenAuth, props: { isLogout: true } },
16
+ // Routes for single page application working with activity_notification REST API backend for users
17
+ {
18
+ path: '/notifications',
19
+ name: 'AuthenticatedUserNotificationsIndex',
20
+ component: NotificationsIndex,
21
+ props: () => ({ target_type: 'users', target: store.getters.currentUser }),
22
+ meta: { requiresAuth: true }
23
+ },
24
+ {
25
+ path: '/subscriptions',
26
+ name: 'AuthenticatedUserSubscriptionsIndex',
27
+ component: SubscriptionsIndex,
28
+ props: () => ({ target_type: 'users', target: store.getters.currentUser }),
29
+ meta: { requiresAuth: true }
30
+ },
31
+ // Routes for single page application working with activity_notification REST API backend for admins
32
+ {
33
+ path: '/admins/notifications',
34
+ name: 'AuthenticatedAdminNotificationsIndex',
35
+ component: NotificationsIndex,
36
+ props: () => ({ target_type: 'admins', targetApiPath: 'admins', target: store.getters.currentUser.admin }),
37
+ meta: { requiresAuth: true }
38
+ },
39
+ {
40
+ path: '/admins/subscriptions',
41
+ name: 'AuthenticatedAdminSubscriptionsIndex',
42
+ component: SubscriptionsIndex,
43
+ props: () => ({ target_type: 'admins', targetApiPath: 'admins', target: store.getters.currentUser.admin }),
44
+ meta: { requiresAuth: true }
45
+ },
46
+ // Routes for single page application working with activity_notification REST API backend for unauthenticated targets
47
+ {
48
+ path: '/:target_type/:target_id/notifications',
49
+ name: 'UnauthenticatedTargetNotificationsIndex',
50
+ component: NotificationsIndex,
51
+ props : true
52
+ },
53
+ {
54
+ path: '/:target_type/:target_id/subscriptions',
55
+ name: 'UnauthenticatedTargetSubscriptionsIndex',
56
+ component: SubscriptionsIndex,
57
+ props : true
58
+ }
59
+ ]
60
+
61
+ const router = new VueRouter({
62
+ routes
63
+ })
64
+
65
+ router.beforeEach((to, from, next) => {
66
+ if (to.matched.some(record => record.meta.requiresAuth) && !store.getters.userSignedIn) {
67
+ next({ path: '/login', query: { redirect: to.fullPath }});
68
+ } else {
69
+ next();
70
+ }
71
+ })
72
+
73
+ export default router
@@ -0,0 +1,37 @@
1
+ import Vue from 'vue'
2
+ import Vuex from 'vuex'
3
+ import createPersistedState from "vuex-persistedstate"
4
+
5
+ Vue.use(Vuex)
6
+
7
+ export default new Vuex.Store({
8
+ state: {
9
+ signedInStatus: false,
10
+ currentUser: null,
11
+ authHeaders: {}
12
+ },
13
+ mutations: {
14
+ signIn(state, { user, authHeaders }) {
15
+ state.currentUser = user;
16
+ state.authHeaders = authHeaders;
17
+ state.signedInStatus = true;
18
+ },
19
+ signOut(state) {
20
+ state.signedInStatus = false;
21
+ state.currentUser = null;
22
+ state.authHeaders = {};
23
+ }
24
+ },
25
+ getters: {
26
+ userSignedIn(state) {
27
+ return state.signedInStatus;
28
+ },
29
+ currentUser(state) {
30
+ return state.currentUser;
31
+ },
32
+ authHeaders(state) {
33
+ return state.authHeaders;
34
+ }
35
+ },
36
+ plugins: [createPersistedState({storage: window.sessionStorage})]
37
+ });
@@ -1,12 +1,23 @@
1
- unless ENV['AN_TEST_DB'] == 'mongodb'
2
- class Admin < ActiveRecord::Base
1
+ module AdminModel
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
3
5
  belongs_to :user
4
6
  validates :user, presence: true
5
7
 
6
8
  acts_as_notification_target email_allowed: false,
7
9
  subscription_allowed: true,
10
+ action_cable_allowed: true, action_cable_with_devise: true,
8
11
  devise_resource: :user,
9
- printable_name: ->(admin) { "admin (#{admin.user.name})" }
12
+ current_devise_target: ->(current_user) { current_user.admin },
13
+ printable_name: ->(admin) { "#{admin.user.name} (admin)" }
14
+ end
15
+ end
16
+
17
+ unless ENV['AN_TEST_DB'] == 'mongodb'
18
+ class Admin < ActiveRecord::Base
19
+ include AdminModel
20
+ default_scope { order(:id) }
10
21
  end
11
22
  else
12
23
  require 'mongoid'
@@ -15,16 +26,10 @@ else
15
26
  include Mongoid::Timestamps
16
27
  include GlobalID::Identification
17
28
 
18
- belongs_to :user
19
- validates :user, presence: true
20
-
21
29
  field :phone_number, type: String
22
30
  field :slack_username, type: String
23
31
 
24
32
  include ActivityNotification::Models
25
- acts_as_notification_target email_allowed: false,
26
- subscription_allowed: true,
27
- devise_resource: :user,
28
- printable_name: ->(admin) { "admin (#{admin.user.name})" }
33
+ include AdminModel
29
34
  end
30
35
  end
@@ -1,20 +1,38 @@
1
- unless ENV['AN_TEST_DB'] == 'mongodb'
2
- class Article < ActiveRecord::Base
1
+ module ArticleModel
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
3
5
  belongs_to :user
4
6
  has_many :comments, dependent: :destroy
5
- has_many :commented_users, through: :comments, source: :user
6
7
  validates :user, presence: true
7
8
 
8
9
  acts_as_notifiable :users,
9
10
  targets: ->(article) { User.all.to_a - [article.user] },
10
11
  notifier: :user, email_allowed: true,
12
+ action_cable_allowed: true, action_cable_api_allowed: true,
13
+ printable_name: ->(article) { "new article \"#{article.title}\"" },
14
+ dependent_notifications: :delete_all
15
+
16
+ acts_as_notifiable :admins,
17
+ targets: ->(article) { Admin.all.to_a },
18
+ notifier: :user,
19
+ action_cable_allowed: true, action_cable_api_allowed: true,
20
+ tracked: Rails.env.test? ? {only: []} : { only: [:create, :update], action_cable_rendering: { fallback: :default } },
11
21
  printable_name: ->(article) { "new article \"#{article.title}\"" },
12
22
  dependent_notifications: :delete_all
23
+
13
24
  acts_as_notification_group printable_name: ->(article) { "article \"#{article.title}\"" }
25
+ end
14
26
 
15
- def author?(user)
16
- self.user == user
17
- end
27
+ def author?(user)
28
+ self.user == user
29
+ end
30
+ end
31
+
32
+ unless ENV['AN_TEST_DB'] == 'mongodb'
33
+ class Article < ActiveRecord::Base
34
+ include ArticleModel
35
+ has_many :commented_users, through: :comments, source: :user
18
36
  end
19
37
  else
20
38
  require 'mongoid'
@@ -23,27 +41,14 @@ else
23
41
  include Mongoid::Timestamps
24
42
  include GlobalID::Identification
25
43
 
26
- belongs_to :user
27
- has_many :comments, dependent: :destroy
28
- validates :user, presence: true
29
-
30
44
  field :title, type: String
31
45
  field :body, type: String
32
46
 
33
47
  include ActivityNotification::Models
34
- acts_as_notifiable :users,
35
- targets: ->(article) { User.all.to_a - [article.user] },
36
- notifier: :user, email_allowed: true,
37
- printable_name: ->(article) { "new article \"#{article.title}\"" },
38
- dependent_notifications: :delete_all
39
- acts_as_notification_group printable_name: ->(article) { "article \"#{article.title}\"" }
48
+ include ArticleModel
40
49
 
41
50
  def commented_users
42
51
  User.where(:id.in => comments.pluck(:user_id))
43
52
  end
44
-
45
- def author?(user)
46
- self.user == user
47
- end
48
53
  end
49
54
  end
@@ -1,20 +1,24 @@
1
- unless ENV['AN_TEST_DB'] == 'mongodb'
2
- class Comment < ActiveRecord::Base
1
+ module CommentModel
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
3
5
  belongs_to :article
4
6
  belongs_to :user
5
7
  validates :article, presence: true
6
8
  validates :user, presence: true
7
9
 
8
10
  acts_as_notifiable :users,
9
- targets: ->(comment, key) { ([comment.article.user] + comment.article.commented_users.to_a - [comment.user]).uniq },
11
+ targets: ->(comment, key) { ([comment.article.user] + comment.article.reload.commented_users.to_a - [comment.user]).uniq },
10
12
  group: :article, notifier: :user, email_allowed: true,
13
+ action_cable_allowed: true, action_cable_api_allowed: true,
11
14
  parameters: { 'test_default_param' => '1' },
12
15
  notifiable_path: :article_notifiable_path,
13
16
  printable_name: ->(comment) { "comment \"#{comment.body}\"" },
14
17
  dependent_notifications: :update_group_and_delete_all
15
18
 
16
19
  require 'custom_optional_targets/console_output'
17
- optional_targets = { CustomOptionalTarget::ConsoleOutput => {} }
20
+ optional_targets = {}
21
+ # optional_targets = optional_targets.merge(CustomOptionalTarget::ConsoleOutput => {})
18
22
  if ENV['OPTIONAL_TARGET_AMAZON_SNS']
19
23
  require 'activity_notification/optional_targets/amazon_sns'
20
24
  if ENV['OPTIONAL_TARGET_AMAZON_SNS_TOPIC_ARN']
@@ -37,20 +41,30 @@ unless ENV['AN_TEST_DB'] == 'mongodb'
37
41
  }
38
42
  )
39
43
  end
40
- acts_as_notifiable :admins, targets: [Admin.first].compact,
44
+ acts_as_notifiable :admins,
45
+ targets: ->(comment) { Admin.all.to_a },
41
46
  group: :article, notifier: :user, notifiable_path: :article_notifiable_path,
42
- tracked: { only: [:create] },
47
+ action_cable_allowed: true, action_cable_api_allowed: true,
48
+ tracked: Rails.env.test? ? {only: []} : { only: [:create], action_cable_rendering: { fallback: :default } },
43
49
  printable_name: ->(comment) { "comment \"#{comment.body}\"" },
44
50
  dependent_notifications: :delete_all,
45
51
  optional_targets: optional_targets
46
52
 
47
- def article_notifiable_path
48
- article_path(article)
49
- end
53
+ acts_as_group
54
+ end
50
55
 
51
- def author?(user)
52
- self.user == user
53
- end
56
+ def article_notifiable_path
57
+ article_path(article)
58
+ end
59
+
60
+ def author?(user)
61
+ self.user == user
62
+ end
63
+ end
64
+
65
+ unless ENV['AN_TEST_DB'] == 'mongodb'
66
+ class Comment < ActiveRecord::Base
67
+ include CommentModel
54
68
  end
55
69
  else
56
70
  require 'mongoid'
@@ -59,58 +73,9 @@ else
59
73
  include Mongoid::Timestamps
60
74
  include GlobalID::Identification
61
75
 
62
- belongs_to :article
63
- belongs_to :user
64
- validates :article, presence: true
65
- validates :user, presence: true
66
76
  field :body, type: String
67
77
 
68
78
  include ActivityNotification::Models
69
- acts_as_notifiable :users,
70
- targets: ->(comment, key) { ([comment.article.user] + comment.article.commented_users.to_a - [comment.user]).uniq },
71
- group: :article, notifier: :user, email_allowed: true,
72
- parameters: { 'test_default_param' => '1' },
73
- notifiable_path: :article_notifiable_path,
74
- printable_name: ->(comment) { "comment \"#{comment.body}\"" },
75
- dependent_notifications: :update_group_and_delete_all
76
-
77
- require 'custom_optional_targets/console_output'
78
- optional_targets = { CustomOptionalTarget::ConsoleOutput => {} }
79
- if ENV['OPTIONAL_TARGET_AMAZON_SNS']
80
- require 'activity_notification/optional_targets/amazon_sns'
81
- if ENV['OPTIONAL_TARGET_AMAZON_SNS_TOPIC_ARN']
82
- optional_targets = optional_targets.merge(
83
- ActivityNotification::OptionalTarget::AmazonSNS => { topic_arn: ENV['OPTIONAL_TARGET_AMAZON_SNS_TOPIC_ARN'] }
84
- )
85
- elsif ENV['OPTIONAL_TARGET_AMAZON_SNS_PHONE_NUMBER']
86
- optional_targets = optional_targets.merge(
87
- ActivityNotification::OptionalTarget::AmazonSNS => { phone_number: :phone_number }
88
- )
89
- end
90
- end
91
- if ENV['OPTIONAL_TARGET_SLACK']
92
- require 'activity_notification/optional_targets/slack'
93
- optional_targets = optional_targets.merge(
94
- ActivityNotification::OptionalTarget::Slack => {
95
- webhook_url: ENV['OPTIONAL_TARGET_SLACK_WEBHOOK_URL'], target_username: :slack_username,
96
- channel: ENV['OPTIONAL_TARGET_SLACK_CHANNEL'] || 'activity_notification',
97
- username: 'ActivityNotification', icon_emoji: ":ghost:"
98
- }
99
- )
100
- end
101
- acts_as_notifiable :admins, targets: [Admin.first].compact,
102
- group: :article, notifier: :user, notifiable_path: :article_notifiable_path,
103
- tracked: { only: [:create] },
104
- printable_name: ->(comment) { "comment \"#{comment.body}\"" },
105
- dependent_notifications: :delete_all,
106
- optional_targets: optional_targets
107
-
108
- def article_notifiable_path
109
- article_path(article)
110
- end
111
-
112
- def author?(user)
113
- self.user == user
114
- end
79
+ include CommentModel
115
80
  end
116
81
  end
@@ -5,6 +5,7 @@ else
5
5
  class Dummy::DummyBase
6
6
  include Mongoid::Document
7
7
  include Mongoid::Timestamps
8
+ include GlobalID::Identification
8
9
  include ActivityNotification::Models
9
10
  end
10
11
  end
@@ -3,10 +3,19 @@ unless ENV['AN_TEST_DB'] == 'mongodb'
3
3
  self.table_name = :articles
4
4
  include ActivityNotification::Group
5
5
  end
6
+
7
+ def printable_target_name
8
+ "dummy"
9
+ end
10
+
11
+ def printable_group_name
12
+ "dummy"
13
+ end
6
14
  else
7
15
  class Dummy::DummyGroup
8
16
  include Mongoid::Document
9
17
  include Mongoid::Timestamps
18
+ include GlobalID::Identification
10
19
  include ActivityNotification::Models
11
20
  include ActivityNotification::Group
12
21
  field :title, type: String
@@ -7,6 +7,7 @@ else
7
7
  class Dummy::DummyNotifiable
8
8
  include Mongoid::Document
9
9
  include Mongoid::Timestamps
10
+ include GlobalID::Identification
10
11
  include ActivityNotification::Models
11
12
  include ActivityNotification::Notifiable
12
13
  field :title, type: String