activity_notification 2.4.1 → 2.5.0

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 (250) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/app/jobs/activity_notification/cascading_notification_job.rb +123 -0
  4. data/docs/Functions.md +197 -1
  5. data/lib/activity_notification/apis/cascading_notification_api.rb +208 -0
  6. data/lib/activity_notification/apis/notification_api.rb +3 -0
  7. data/lib/activity_notification/config.rb +10 -0
  8. data/lib/activity_notification/mailers/helpers.rb +27 -1
  9. data/lib/activity_notification/version.rb +1 -1
  10. data/lib/generators/templates/activity_notification.rb +8 -0
  11. metadata +5 -441
  12. data/.codeclimate.yml +0 -33
  13. data/.coveralls.yml +0 -1
  14. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -22
  15. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
  16. data/.github/pull_request_template.md +0 -13
  17. data/.github/workflows/build.yml +0 -100
  18. data/.gitignore +0 -74
  19. data/.rspec +0 -3
  20. data/.rubocop.yml +0 -1157
  21. data/.yardopts +0 -6
  22. data/CHANGELOG.md +0 -452
  23. data/Gemfile +0 -31
  24. data/Procfile +0 -2
  25. data/Rakefile +0 -28
  26. data/activity_notification.gemspec +0 -44
  27. data/ai-curated-specs/issues/172/design.md +0 -220
  28. data/ai-curated-specs/issues/172/tasks.md +0 -326
  29. data/ai-curated-specs/issues/188/design.md +0 -227
  30. data/ai-curated-specs/issues/188/requirements.md +0 -78
  31. data/ai-curated-specs/issues/188/tasks.md +0 -203
  32. data/ai-curated-specs/issues/188/upstream-contributions.md +0 -592
  33. data/ai-curated-specs/issues/50/design.md +0 -235
  34. data/ai-curated-specs/issues/50/requirements.md +0 -49
  35. data/ai-curated-specs/issues/50/tasks.md +0 -232
  36. data/bin/_dynamodblocal +0 -4
  37. data/bin/bundle_update.sh +0 -7
  38. data/bin/deploy_on_heroku.sh +0 -16
  39. data/bin/install_dynamodblocal.sh +0 -5
  40. data/bin/start_dynamodblocal.sh +0 -47
  41. data/bin/stop_dynamodblocal.sh +0 -34
  42. data/gemfiles/Gemfile.rails-5.0 +0 -25
  43. data/gemfiles/Gemfile.rails-5.1 +0 -25
  44. data/gemfiles/Gemfile.rails-5.2 +0 -24
  45. data/gemfiles/Gemfile.rails-6.0 +0 -23
  46. data/gemfiles/Gemfile.rails-6.1 +0 -22
  47. data/gemfiles/Gemfile.rails-7.0 +0 -25
  48. data/gemfiles/Gemfile.rails-7.1 +0 -23
  49. data/gemfiles/Gemfile.rails-7.2 +0 -23
  50. data/gemfiles/Gemfile.rails-8.0 +0 -24
  51. data/package.json +0 -8
  52. data/spec/channels/notification_api_channel_shared_examples.rb +0 -59
  53. data/spec/channels/notification_api_channel_spec.rb +0 -49
  54. data/spec/channels/notification_api_with_devise_channel_spec.rb +0 -76
  55. data/spec/channels/notification_channel_shared_examples.rb +0 -59
  56. data/spec/channels/notification_channel_spec.rb +0 -48
  57. data/spec/channels/notification_with_devise_channel_spec.rb +0 -97
  58. data/spec/concerns/apis/notification_api_spec.rb +0 -1627
  59. data/spec/concerns/apis/subscription_api_spec.rb +0 -474
  60. data/spec/concerns/common_spec.rb +0 -213
  61. data/spec/concerns/models/group_spec.rb +0 -61
  62. data/spec/concerns/models/notifiable_spec.rb +0 -782
  63. data/spec/concerns/models/notifier_spec.rb +0 -71
  64. data/spec/concerns/models/subscriber_spec.rb +0 -800
  65. data/spec/concerns/models/target_spec.rb +0 -1285
  66. data/spec/concerns/renderable_spec.rb +0 -129
  67. data/spec/config_spec.rb +0 -85
  68. data/spec/controllers/common_controller_spec.rb +0 -25
  69. data/spec/controllers/controller_spec_utility.rb +0 -100
  70. data/spec/controllers/dummy_common_controller.rb +0 -5
  71. data/spec/controllers/notifications_api_controller_shared_examples.rb +0 -619
  72. data/spec/controllers/notifications_api_controller_spec.rb +0 -19
  73. data/spec/controllers/notifications_api_with_devise_controller_spec.rb +0 -60
  74. data/spec/controllers/notifications_controller_shared_examples.rb +0 -743
  75. data/spec/controllers/notifications_controller_spec.rb +0 -11
  76. data/spec/controllers/notifications_with_devise_controller_spec.rb +0 -97
  77. data/spec/controllers/subscriptions_api_controller_shared_examples.rb +0 -750
  78. data/spec/controllers/subscriptions_api_controller_spec.rb +0 -19
  79. data/spec/controllers/subscriptions_api_with_devise_controller_spec.rb +0 -60
  80. data/spec/controllers/subscriptions_controller_shared_examples.rb +0 -946
  81. data/spec/controllers/subscriptions_controller_spec.rb +0 -11
  82. data/spec/controllers/subscriptions_with_devise_controller_spec.rb +0 -97
  83. data/spec/factories/admins.rb +0 -5
  84. data/spec/factories/articles.rb +0 -5
  85. data/spec/factories/comments.rb +0 -6
  86. data/spec/factories/dummy/dummy_group.rb +0 -4
  87. data/spec/factories/dummy/dummy_notifiable.rb +0 -4
  88. data/spec/factories/dummy/dummy_notifier.rb +0 -4
  89. data/spec/factories/dummy/dummy_subscriber.rb +0 -4
  90. data/spec/factories/dummy/dummy_target.rb +0 -4
  91. data/spec/factories/notifications.rb +0 -7
  92. data/spec/factories/subscriptions.rb +0 -8
  93. data/spec/factories/users.rb +0 -11
  94. data/spec/generators/controllers_generator_spec.rb +0 -85
  95. data/spec/generators/install_generator_spec.rb +0 -43
  96. data/spec/generators/migration/migration_generator_spec.rb +0 -80
  97. data/spec/generators/models_generator_spec.rb +0 -96
  98. data/spec/generators/views_generator_spec.rb +0 -195
  99. data/spec/helpers/polymorphic_helpers_spec.rb +0 -89
  100. data/spec/helpers/view_helpers_spec.rb +0 -547
  101. data/spec/jobs/notification_resilience_job_spec.rb +0 -167
  102. data/spec/jobs/notify_all_job_spec.rb +0 -23
  103. data/spec/jobs/notify_job_spec.rb +0 -23
  104. data/spec/jobs/notify_to_job_spec.rb +0 -23
  105. data/spec/mailers/mailer_spec.rb +0 -214
  106. data/spec/mailers/notification_resilience_spec.rb +0 -263
  107. data/spec/models/dummy/dummy_group_spec.rb +0 -10
  108. data/spec/models/dummy/dummy_notifiable_spec.rb +0 -10
  109. data/spec/models/dummy/dummy_notifier_spec.rb +0 -10
  110. data/spec/models/dummy/dummy_subscriber_spec.rb +0 -8
  111. data/spec/models/dummy/dummy_target_spec.rb +0 -10
  112. data/spec/models/notification_spec.rb +0 -472
  113. data/spec/models/subscription_spec.rb +0 -215
  114. data/spec/optional_targets/action_cable_api_channel_spec.rb +0 -34
  115. data/spec/optional_targets/action_cable_channel_spec.rb +0 -41
  116. data/spec/optional_targets/amazon_sns_spec.rb +0 -47
  117. data/spec/optional_targets/base_spec.rb +0 -45
  118. data/spec/optional_targets/slack_spec.rb +0 -44
  119. data/spec/orm/dynamoid_spec.rb +0 -115
  120. data/spec/rails_app/Rakefile +0 -15
  121. data/spec/rails_app/app/assets/config/manifest.js +0 -3
  122. data/spec/rails_app/app/assets/images/.keep +0 -0
  123. data/spec/rails_app/app/assets/javascripts/application.js +0 -3
  124. data/spec/rails_app/app/assets/javascripts/cable.js +0 -12
  125. data/spec/rails_app/app/assets/stylesheets/application.css +0 -15
  126. data/spec/rails_app/app/assets/stylesheets/reset.css +0 -85
  127. data/spec/rails_app/app/assets/stylesheets/style.css +0 -244
  128. data/spec/rails_app/app/controllers/admins_controller.rb +0 -21
  129. data/spec/rails_app/app/controllers/application_controller.rb +0 -5
  130. data/spec/rails_app/app/controllers/articles_controller.rb +0 -67
  131. data/spec/rails_app/app/controllers/comments_controller.rb +0 -36
  132. data/spec/rails_app/app/controllers/concerns/.keep +0 -0
  133. data/spec/rails_app/app/controllers/spa_controller.rb +0 -7
  134. data/spec/rails_app/app/controllers/users/notifications_controller.rb +0 -2
  135. data/spec/rails_app/app/controllers/users/notifications_with_devise_controller.rb +0 -2
  136. data/spec/rails_app/app/controllers/users/subscriptions_controller.rb +0 -2
  137. data/spec/rails_app/app/controllers/users/subscriptions_with_devise_controller.rb +0 -2
  138. data/spec/rails_app/app/controllers/users_controller.rb +0 -26
  139. data/spec/rails_app/app/helpers/application_helper.rb +0 -2
  140. data/spec/rails_app/app/helpers/devise_helper.rb +0 -2
  141. data/spec/rails_app/app/javascript/App.vue +0 -40
  142. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +0 -82
  143. data/spec/rails_app/app/javascript/components/Top.vue +0 -98
  144. data/spec/rails_app/app/javascript/components/notifications/Index.vue +0 -200
  145. data/spec/rails_app/app/javascript/components/notifications/Notification.vue +0 -133
  146. data/spec/rails_app/app/javascript/components/notifications/NotificationContent.vue +0 -122
  147. data/spec/rails_app/app/javascript/components/subscriptions/Index.vue +0 -279
  148. data/spec/rails_app/app/javascript/components/subscriptions/NewSubscription.vue +0 -112
  149. data/spec/rails_app/app/javascript/components/subscriptions/NotificationKey.vue +0 -141
  150. data/spec/rails_app/app/javascript/components/subscriptions/Subscription.vue +0 -226
  151. data/spec/rails_app/app/javascript/config/development.js +0 -5
  152. data/spec/rails_app/app/javascript/config/environment.js +0 -7
  153. data/spec/rails_app/app/javascript/config/production.js +0 -5
  154. data/spec/rails_app/app/javascript/config/test.js +0 -5
  155. data/spec/rails_app/app/javascript/packs/application.js +0 -18
  156. data/spec/rails_app/app/javascript/packs/spa.js +0 -14
  157. data/spec/rails_app/app/javascript/router/index.js +0 -73
  158. data/spec/rails_app/app/javascript/store/index.js +0 -37
  159. data/spec/rails_app/app/mailers/.keep +0 -0
  160. data/spec/rails_app/app/mailers/custom_notification_mailer.rb +0 -5
  161. data/spec/rails_app/app/models/admin.rb +0 -35
  162. data/spec/rails_app/app/models/article.rb +0 -54
  163. data/spec/rails_app/app/models/comment.rb +0 -81
  164. data/spec/rails_app/app/models/dummy/dummy_base.rb +0 -11
  165. data/spec/rails_app/app/models/dummy/dummy_group.rb +0 -23
  166. data/spec/rails_app/app/models/dummy/dummy_notifiable.rb +0 -15
  167. data/spec/rails_app/app/models/dummy/dummy_notifiable_target.rb +0 -27
  168. data/spec/rails_app/app/models/dummy/dummy_notifier.rb +0 -15
  169. data/spec/rails_app/app/models/dummy/dummy_subscriber.rb +0 -14
  170. data/spec/rails_app/app/models/dummy/dummy_target.rb +0 -16
  171. data/spec/rails_app/app/models/user.rb +0 -73
  172. data/spec/rails_app/app/views/activity_notification/mailer/dummy_subscribers/test_key.text.erb +0 -1
  173. data/spec/rails_app/app/views/activity_notification/notifications/default/article/_update.html.erb +0 -146
  174. data/spec/rails_app/app/views/activity_notification/notifications/default/custom/_path_test.html.erb +0 -1
  175. data/spec/rails_app/app/views/activity_notification/notifications/default/custom/_test.html.erb +0 -1
  176. data/spec/rails_app/app/views/activity_notification/notifications/users/_custom_index.html.erb +0 -1
  177. data/spec/rails_app/app/views/activity_notification/notifications/users/custom/_test.html.erb +0 -1
  178. data/spec/rails_app/app/views/activity_notification/notifications/users/overridden/custom/_test.html.erb +0 -1
  179. data/spec/rails_app/app/views/activity_notification/optional_targets/admins/amazon_sns/comment/_default.text.erb +0 -10
  180. data/spec/rails_app/app/views/articles/_form.html.erb +0 -24
  181. data/spec/rails_app/app/views/articles/edit.html.erb +0 -8
  182. data/spec/rails_app/app/views/articles/index.html.erb +0 -113
  183. data/spec/rails_app/app/views/articles/new.html.erb +0 -7
  184. data/spec/rails_app/app/views/articles/show.html.erb +0 -49
  185. data/spec/rails_app/app/views/layouts/_header.html.erb +0 -46
  186. data/spec/rails_app/app/views/layouts/application.html.erb +0 -15
  187. data/spec/rails_app/app/views/spa/index.html.erb +0 -2
  188. data/spec/rails_app/babel.config.js +0 -72
  189. data/spec/rails_app/bin/bundle +0 -3
  190. data/spec/rails_app/bin/rails +0 -4
  191. data/spec/rails_app/bin/rake +0 -4
  192. data/spec/rails_app/bin/setup +0 -29
  193. data/spec/rails_app/bin/webpack +0 -18
  194. data/spec/rails_app/bin/webpack-dev-server +0 -18
  195. data/spec/rails_app/config/application.rb +0 -54
  196. data/spec/rails_app/config/boot.rb +0 -5
  197. data/spec/rails_app/config/cable.yml +0 -8
  198. data/spec/rails_app/config/database.yml +0 -36
  199. data/spec/rails_app/config/dynamoid.rb +0 -13
  200. data/spec/rails_app/config/environment.rb +0 -26
  201. data/spec/rails_app/config/environments/development.rb +0 -60
  202. data/spec/rails_app/config/environments/production.rb +0 -85
  203. data/spec/rails_app/config/environments/test.rb +0 -53
  204. data/spec/rails_app/config/initializers/activity_notification.rb +0 -104
  205. data/spec/rails_app/config/initializers/assets.rb +0 -11
  206. data/spec/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  207. data/spec/rails_app/config/initializers/cookies_serializer.rb +0 -3
  208. data/spec/rails_app/config/initializers/copy_it.aws.rb.template +0 -6
  209. data/spec/rails_app/config/initializers/devise.rb +0 -278
  210. data/spec/rails_app/config/initializers/devise_token_auth.rb +0 -55
  211. data/spec/rails_app/config/initializers/filter_parameter_logging.rb +0 -4
  212. data/spec/rails_app/config/initializers/inflections.rb +0 -16
  213. data/spec/rails_app/config/initializers/mime_types.rb +0 -4
  214. data/spec/rails_app/config/initializers/mysql.rb +0 -9
  215. data/spec/rails_app/config/initializers/session_store.rb +0 -3
  216. data/spec/rails_app/config/initializers/wrap_parameters.rb +0 -14
  217. data/spec/rails_app/config/initializers/zeitwerk.rb +0 -10
  218. data/spec/rails_app/config/locales/activity_notification.en.yml +0 -26
  219. data/spec/rails_app/config/locales/devise.en.yml +0 -62
  220. data/spec/rails_app/config/mongoid.yml +0 -13
  221. data/spec/rails_app/config/routes.rb +0 -50
  222. data/spec/rails_app/config/secrets.yml +0 -22
  223. data/spec/rails_app/config/webpack/development.js +0 -5
  224. data/spec/rails_app/config/webpack/environment.js +0 -7
  225. data/spec/rails_app/config/webpack/loaders/vue.js +0 -6
  226. data/spec/rails_app/config/webpack/production.js +0 -5
  227. data/spec/rails_app/config/webpack/test.js +0 -5
  228. data/spec/rails_app/config/webpacker.yml +0 -97
  229. data/spec/rails_app/config.ru +0 -4
  230. data/spec/rails_app/db/migrate/20160716000000_create_test_tables.rb +0 -42
  231. data/spec/rails_app/db/migrate/20181209000000_create_activity_notification_tables.rb +0 -33
  232. data/spec/rails_app/db/migrate/20191201000000_add_tokens_to_users.rb +0 -10
  233. data/spec/rails_app/db/schema.rb +0 -98
  234. data/spec/rails_app/db/seeds.rb +0 -95
  235. data/spec/rails_app/lib/custom_optional_targets/console_output.rb +0 -16
  236. data/spec/rails_app/lib/custom_optional_targets/raise_error.rb +0 -14
  237. data/spec/rails_app/lib/custom_optional_targets/wrong_target.rb +0 -13
  238. data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +0 -29
  239. data/spec/rails_app/package.json +0 -23
  240. data/spec/rails_app/postcss.config.js +0 -12
  241. data/spec/rails_app/public/404.html +0 -67
  242. data/spec/rails_app/public/422.html +0 -67
  243. data/spec/rails_app/public/500.html +0 -66
  244. data/spec/rails_app/public/favicon.ico +0 -0
  245. data/spec/roles/acts_as_group_spec.rb +0 -30
  246. data/spec/roles/acts_as_notifiable_spec.rb +0 -432
  247. data/spec/roles/acts_as_notifier_spec.rb +0 -30
  248. data/spec/roles/acts_as_target_spec.rb +0 -36
  249. data/spec/spec_helper.rb +0 -56
  250. data/spec/version_spec.rb +0 -31
@@ -1,220 +0,0 @@
1
- # Design Document: Bulk destroy notifications API
2
-
3
- ## Issue Summary
4
- GitHub Issue [#172](https://github.com/simukappu/activity_notification/issues/172) requests the ability to delete more than one notification for a target. Currently, only single notification deletion is available through the `destroy` API. The user wants a `bulk_destroy` API or provision to create custom APIs for bulk destroying notifications.
5
-
6
- ## Current State Analysis
7
-
8
- ### Existing Destroy Functionality
9
- - **Single Destroy**: `DELETE /:target_type/:target_id/notifications/:id`
10
- - Implemented in `NotificationsController#destroy`
11
- - API version in `NotificationsApiController#destroy`
12
- - Simply calls `@notification.destroy` on individual notification
13
-
14
- ### Existing Bulk Operations Pattern
15
- - **Bulk Open**: `POST /:target_type/:target_id/notifications/open_all`
16
- - Implemented in `NotificationsController#open_all`
17
- - Uses `@target.open_all_notifications(params)`
18
- - Backend implementation in `NotificationApi#open_all_of`
19
- - Uses `update_all(opened_at: opened_at)` for efficient bulk updates
20
-
21
- ## Proposed Implementation
22
-
23
- ### 1. Backend API Method (NotificationApi)
24
- **File**: `lib/activity_notification/apis/notification_api.rb`
25
-
26
- Add a new class method `destroy_all_of` following the pattern of `open_all_of`:
27
-
28
- ```ruby
29
- # Destroys all notifications of the target matching the filter criteria.
30
- #
31
- # @param [Object] target Target of the notifications to destroy
32
- # @param [Hash] options Options for filtering notifications to destroy
33
- # @option options [String] :filtered_by_type (nil) Notifiable type for filter
34
- # @option options [Object] :filtered_by_group (nil) Group instance for filter
35
- # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
36
- # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
37
- # @option options [String] :filtered_by_key (nil) Key of the notification for filter
38
- # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
39
- # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
40
- # @option options [Array] :ids (nil) Array of specific notification IDs to destroy
41
- # @return [Array<Notification>] Destroyed notification records
42
- def destroy_all_of(target, options = {})
43
- ```
44
-
45
- ### 2. Target Model Method
46
- **File**: `lib/activity_notification/models/concerns/target.rb`
47
-
48
- Add instance method `destroy_all_notifications` following the pattern of `open_all_notifications`:
49
-
50
- ```ruby
51
- # Destroys all notifications of the target matching the filter criteria.
52
- #
53
- # @param [Hash] options Options for filtering notifications to destroy
54
- # @option options [String] :filtered_by_type (nil) Notifiable type for filter
55
- # @option options [Object] :filtered_by_group (nil) Group instance for filter
56
- # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
57
- # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
58
- # @option options [String] :filtered_by_key (nil) Key of the notification for filter
59
- # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
60
- # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
61
- # @option options [Array] :ids (nil) Array of specific notification IDs to destroy
62
- # @return [Array<Notification>] Destroyed notification records
63
- def destroy_all_notifications(options = {})
64
- ```
65
-
66
- ### 3. Controller Actions
67
-
68
- #### Web Controller
69
- **File**: `app/controllers/activity_notification/notifications_controller.rb`
70
-
71
- Add new action `destroy_all`:
72
-
73
- ```ruby
74
- # Destroys all notifications of the target matching filter criteria.
75
- #
76
- # POST /:target_type/:target_id/notifications/destroy_all
77
- # @overload destroy_all(params)
78
- # @param [Hash] params Request parameters
79
- # @option params [String] :filter (nil) Filter option to load notification index by their status (Nothing as auto, 'opened' or 'unopened')
80
- # @option params [String] :limit (nil) Maximum number of notifications to return
81
- # @option params [String] :without_grouping ('false') Whether notification index will include group members
82
- # @option params [String] :with_group_members ('false') Whether notification index will include group members
83
- # @option params [String] :filtered_by_type (nil) Notifiable type to filter notifications
84
- # @option params [String] :filtered_by_group_type (nil) Group type to filter notifications, valid with :filtered_by_group_id
85
- # @option params [String] :filtered_by_group_id (nil) Group instance ID to filter notifications, valid with :filtered_by_group_type
86
- # @option params [String] :filtered_by_key (nil) Key of notifications to filter
87
- # @option params [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
88
- # @option params [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
89
- # @option params [Array] :ids (nil) Array of specific notification IDs to destroy
90
- # @option params [String] :reload ('true') Whether notification index will be reloaded
91
- # @return [Response] JavaScript view for ajax request or redirects to back as default
92
- def destroy_all
93
- ```
94
-
95
- #### API Controller
96
- **File**: `app/controllers/activity_notification/notifications_api_controller.rb`
97
-
98
- Add new action `destroy_all`:
99
-
100
- ```ruby
101
- # Destroys all notifications of the target matching filter criteria.
102
- #
103
- # POST /:target_type/:target_id/notifications/destroy_all
104
- # @overload destroy_all(params)
105
- # @param [Hash] params Request parameters
106
- # @option params [String] :filtered_by_type (nil) Notifiable type to filter notifications
107
- # @option params [String] :filtered_by_group_type (nil) Group type to filter notifications, valid with :filtered_by_group_id
108
- # @option params [String] :filtered_by_group_id (nil) Group instance ID to filter notifications, valid with :filtered_by_group_type
109
- # @option params [String] :filtered_by_key (nil) Key of notifications to filter
110
- # @option params [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
111
- # @option params [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
112
- # @option params [Array] :ids (nil) Array of specific notification IDs to destroy
113
- # @return [JSON] count: number of destroyed notification records, notifications: destroyed notifications
114
- def destroy_all
115
- ```
116
-
117
- ### 4. Routes Configuration
118
- **File**: Routes will be automatically generated by the existing `notify_to` helper
119
-
120
- The route will be: `POST /:target_type/:target_id/notifications/destroy_all`
121
-
122
- ### 5. View Templates
123
- **Files**:
124
- - `app/views/activity_notification/notifications/default/destroy_all.js.erb`
125
- - Template generators will need to be updated to include the new view
126
-
127
- ### 6. Swagger API Documentation
128
- **File**: Update Swagger documentation to include the new bulk destroy endpoint
129
-
130
- ### 7. Generator Templates
131
- **Files**: Update controller generator templates to include the new `destroy_all` action:
132
- - `lib/generators/templates/controllers/notifications_api_controller.rb`
133
- - `lib/generators/templates/controllers/notifications_controller.rb`
134
- - `lib/generators/templates/controllers/notifications_with_devise_controller.rb`
135
-
136
- ## Implementation Details
137
-
138
- ### Filter Options Support
139
- The bulk destroy API will support the same filtering options as the existing `open_all` functionality:
140
- - `filtered_by_type`: Filter by notifiable type
141
- - `filtered_by_group_type` + `filtered_by_group_id`: Filter by group
142
- - `filtered_by_key`: Filter by notification key
143
- - `later_than` / `earlier_than`: Filter by time range
144
- - `ids`: Array of specific notification IDs (new option for precise control)
145
-
146
- ### Safety Considerations
147
- 1. **Validation**: Ensure all notifications belong to the specified target
148
- 2. **Permissions**: Leverage existing authentication/authorization patterns
149
- 3. **Soft Delete**: Consider if soft delete should be supported (follow existing destroy pattern)
150
- 4. **Callbacks**: Ensure any existing destroy callbacks are properly triggered
151
-
152
- ### Performance Considerations
153
- 1. **Batch Operations**: Use `destroy_all` for efficient database operations
154
- 2. **Memory Usage**: For large datasets, consider pagination or streaming
155
- 3. **Callbacks**: Balance between performance and callback execution
156
-
157
- ### Error Handling
158
- 1. **Partial Failures**: Handle cases where some notifications can't be destroyed
159
- 2. **Validation Errors**: Provide meaningful error messages
160
- 3. **Authorization Errors**: Consistent with existing error handling patterns
161
-
162
- ## Testing Requirements
163
-
164
- ### Unit Tests
165
- - Test `NotificationApi#destroy_all_of` method
166
- - Test `Target#destroy_all_notifications` method
167
- - Test controller actions for both web and API versions
168
-
169
- ### Integration Tests
170
- - Test complete request/response cycle
171
- - Test with various filter combinations
172
- - Test error scenarios
173
-
174
- ### Performance Tests
175
- - Test with large datasets
176
- - Verify efficient database queries
177
-
178
- ## Migration Considerations
179
- - No database schema changes required
180
- - Backward compatible addition
181
- - Follows existing patterns and conventions
182
-
183
- ## Documentation Updates
184
- - Update README.md with new bulk destroy functionality
185
- - Update API documentation
186
- - Update controller documentation
187
- - Add examples to documentation
188
-
189
- ## Alternative Implementation Options
190
-
191
- ### Option 1: Single Endpoint with Multiple IDs
192
- Instead of filter-based bulk destroy, accept an array of notification IDs:
193
- ```
194
- POST /:target_type/:target_id/notifications/destroy_all
195
- Body: { "ids": [1, 2, 3, 4, 5] }
196
- ```
197
-
198
- ### Option 2: RESTful Bulk Operations
199
- Follow RESTful conventions with a bulk operations endpoint:
200
- ```
201
- POST /:target_type/:target_id/notifications/bulk
202
- Body: { "action": "destroy", "filters": {...} }
203
- ```
204
-
205
- ### Option 3: Query Parameter Approach
206
- Use existing destroy endpoint with query parameters:
207
- ```
208
- DELETE /:target_type/:target_id/notifications?ids[]=1&ids[]=2&ids[]=3
209
- ```
210
-
211
- ## Recommended Approach
212
- The proposed implementation follows the existing pattern established by `open_all` functionality, making it consistent with the current codebase architecture. This approach provides:
213
-
214
- 1. **Consistency**: Matches existing bulk operation patterns
215
- 2. **Flexibility**: Supports various filtering options
216
- 3. **Safety**: Leverages existing validation and authorization
217
- 4. **Performance**: Uses efficient bulk database operations
218
- 5. **Maintainability**: Follows established code organization
219
-
220
- The implementation should prioritize the filter-based approach (similar to `open_all`) while also supporting the `ids` parameter for precise control when needed.
@@ -1,326 +0,0 @@
1
- # Implementation Plan
2
-
3
- ## Problem 1: Mongoid ORM Compatibility Issue with ID Array Filtering
4
-
5
- ### Issue Description
6
- The bulk destroy functionality works correctly with ActiveRecord ORM but fails with Mongoid ORM. Specifically, the test case `context 'with ids options'` in `spec/concerns/apis/notification_api_spec.rb` is failing.
7
-
8
- **Location**: `lib/activity_notification/apis/notification_api.rb` line 440
9
- **Problematic Code**:
10
- ```ruby
11
- target_notifications = target_notifications.where(id: options[:ids])
12
- ```
13
-
14
- ### Root Cause Analysis
15
- The issue stems from different query syntax requirements between ActiveRecord and Mongoid when filtering by an array of IDs:
16
-
17
- 1. **ActiveRecord**: Uses `where(id: [1, 2, 3])` which automatically translates to SQL `WHERE id IN (1, 2, 3)`
18
- 2. **Mongoid**: Requires explicit `$in` operator syntax for array matching: `where(id: { '$in' => [1, 2, 3] })`
19
-
20
- ### Current Implementation Problem
21
- The current implementation uses ActiveRecord syntax:
22
- ```ruby
23
- target_notifications = target_notifications.where(id: options[:ids])
24
- ```
25
-
26
- This works for ActiveRecord but fails for Mongoid because Mongoid doesn't automatically interpret an array as an `$in` operation.
27
-
28
- ### Expected Behavior
29
- - When `options[:ids]` contains `[notification1.id, notification2.id]`, only notifications with those specific IDs should be destroyed
30
- - The filtering should work consistently across both ActiveRecord and Mongoid ORMs
31
- - Other filter options should still be applied in combination with ID filtering
32
-
33
- ### Test Case Analysis
34
- The failing test:
35
- ```ruby
36
- it "destroys notifications with specified IDs only" do
37
- notification_to_destroy = @user_1.notifications.first
38
- described_class.destroy_all_of(@user_1, { ids: [notification_to_destroy.id] })
39
- expect(@user_1.notifications.count).to eq(1)
40
- expect(@user_1.notifications.first).not_to eq(notification_to_destroy)
41
- end
42
- ```
43
-
44
- This test expects that when an array of IDs is provided, only those specific notifications are destroyed.
45
-
46
- ### Solution Strategy
47
- Implement ORM-specific ID filtering logic that:
48
-
49
- 1. **Detection**: Check the current ORM configuration using `ActivityNotification.config.orm`
50
- 2. **ActiveRecord Path**: Use existing `where(id: options[:ids])` syntax
51
- 3. **Mongoid Path**: Use `where(id: { '$in' => options[:ids] })` syntax
52
- 4. **Dynamoid Path**: Use `where(‘id.in‘: options[:ids])` syntax
53
-
54
- ### Implementation Plan
55
- 1. **Conditional Logic**: Add ORM detection in the `destroy_all_of` method
56
- 2. **Mongoid Syntax**: Use `{ '$in' => options[:ids] }` for Mongoid
57
- 3. **Backward Compatibility**: Ensure ActiveRecord continues to work as before
58
- 4. **Testing**: Verify both ORMs work correctly with the new implementation
59
-
60
- ### Code Changes Required
61
- **File**: `lib/activity_notification/apis/notification_api.rb`
62
- **Method**: `destroy_all_of` (around line 440)
63
-
64
- Replace:
65
- ```ruby
66
- if options[:ids].present?
67
- target_notifications = target_notifications.where(id: options[:ids])
68
- end
69
- ```
70
-
71
- With ORM-specific logic:
72
- ```ruby
73
- if options[:ids].present?
74
- case ActivityNotification.config.orm
75
- when :mongoid
76
- target_notifications = target_notifications.where(id: { '$in' => options[:ids] })
77
- when :dynamoid
78
- target_notifications = target_notifications.where('id.in': options[:ids])
79
- else # :active_record
80
- target_notifications = target_notifications.where(id: options[:ids])
81
- end
82
- end
83
- ```
84
-
85
- ### Testing Requirements
86
- 1. **Unit Tests**: Ensure the method works with both ActiveRecord and Mongoid
87
- 2. **Integration Tests**: Verify the complete destroy_all functionality
88
- 3. **Regression Tests**: Ensure existing functionality remains intact
89
-
90
- ### Risk Assessment
91
- - **Low Risk**: The change is isolated to the ID filtering logic
92
- - **Backward Compatible**: ActiveRecord behavior remains unchanged
93
- - **Well-Tested**: Existing test suite will catch any regressions
94
-
95
- ### Future Considerations
96
- - Consider extracting ORM-specific query logic into a helper method if more similar cases arise
97
- - Document the ORM differences for future developers
98
- - Consider adding similar logic to other methods that might have the same issue
99
-
100
- ---
101
-
102
- ## Problem 2: Add IDs Parameter to open_all API
103
-
104
- ### Issue Description
105
- Enhance the `open_all_of` method to support the `ids` parameter functionality, similar to the implementation in `destroy_all_of`. This will allow users to open specific notifications by providing an array of notification IDs.
106
-
107
- ### Current State Analysis
108
-
109
- #### Existing open_all_of Method
110
- **Location**: `lib/activity_notification/apis/notification_api.rb` (around line 415)
111
-
112
- **Current Implementation**:
113
- ```ruby
114
- def open_all_of(target, options = {})
115
- opened_at = options[:opened_at] || Time.current
116
- target_unopened_notifications = target.notifications.unopened_only.filtered_by_options(options)
117
- opened_notifications = target_unopened_notifications.to_a.map { |n| n.opened_at = opened_at; n }
118
- target_unopened_notifications.update_all(opened_at: opened_at)
119
- opened_notifications
120
- end
121
- ```
122
-
123
- **Current Parameters**:
124
- - `opened_at`: Time to set to opened_at of the notification record
125
- - `filtered_by_type`: Notifiable type for filter
126
- - `filtered_by_group`: Group instance for filter
127
- - `filtered_by_group_type`: Group type for filter, valid with :filtered_by_group_id
128
- - `filtered_by_group_id`: Group instance id for filter, valid with :filtered_by_group_type
129
- - `filtered_by_key`: Key of the notification for filter
130
- - `later_than`: ISO 8601 format time to filter notification index later than specified time
131
- - `earlier_than`: ISO 8601 format time to filter notification index earlier than specified time
132
-
133
- ### Proposed Enhancement
134
-
135
- #### Add IDs Parameter Support
136
- Add support for the `ids` parameter to allow opening specific notifications by their IDs, following the same pattern as `destroy_all_of`.
137
-
138
- #### Updated Method Signature
139
- ```ruby
140
- # @option options [Array] :ids (nil) Array of specific notification IDs to open
141
- def open_all_of(target, options = {})
142
- ```
143
-
144
- ### Implementation Strategy
145
- 1. **Reuse existing pattern**: Follow the same ORM-specific ID filtering logic implemented in `destroy_all_of`
146
- 2. **Maintain backward compatibility**: Ensure existing functionality remains unchanged
147
- 3. **Consistent behavior**: Apply ID filtering after other filters, similar to destroy_all_of
148
-
149
- ### Code Changes Required
150
-
151
- #### 1. Update Method Documentation
152
- **File**: `lib/activity_notification/apis/notification_api.rb`
153
-
154
- Add the `ids` parameter to the method documentation:
155
- ```ruby
156
- # @option options [Array] :ids (nil) Array of specific notification IDs to open
157
- ```
158
-
159
- #### 2. Add ID Filtering Logic
160
- Insert the same ORM-specific ID filtering logic used in `destroy_all_of`:
161
-
162
- ```ruby
163
- def open_all_of(target, options = {})
164
- opened_at = options[:opened_at] || Time.current
165
- target_unopened_notifications = target.notifications.unopened_only.filtered_by_options(options)
166
-
167
- # Add ID filtering logic (same as destroy_all_of)
168
- if options[:ids].present?
169
- # :nocov:
170
- case ActivityNotification.config.orm
171
- when :mongoid
172
- target_unopened_notifications = target_unopened_notifications.where(id: { '$in' => options[:ids] })
173
- when :dynamoid
174
- target_unopened_notifications = target_unopened_notifications.where('id.in': options[:ids])
175
- else # :active_record
176
- target_unopened_notifications = target_unopened_notifications.where(id: options[:ids])
177
- end
178
- # :nocov:
179
- end
180
-
181
- opened_notifications = target_unopened_notifications.to_a.map { |n| n.opened_at = opened_at; n }
182
- target_unopened_notifications.update_all(opened_at: opened_at)
183
- opened_notifications
184
- end
185
- ```
186
-
187
- #### 3. Update Controller Actions
188
- The controller actions that use `open_all_of` should be updated to accept and pass through the `ids` parameter:
189
-
190
- **Files to Update**:
191
- - `app/controllers/activity_notification/notifications_controller.rb`
192
- - `app/controllers/activity_notification/notifications_api_controller.rb`
193
-
194
- **Parameter Addition**:
195
- ```ruby
196
- # Add :ids to permitted parameters
197
- params.permit(:ids => [])
198
- ```
199
-
200
- #### 4. Update API Documentation
201
- **File**: `lib/activity_notification/controllers/concerns/swagger/notifications_api.rb`
202
-
203
- Add `ids` parameter to the Swagger documentation for the open_all endpoint:
204
- ```ruby
205
- parameter do
206
- key :name, :ids
207
- key :in, :query
208
- key :description, 'Array of specific notification IDs to open'
209
- key :required, false
210
- key :type, :array
211
- items do
212
- key :type, :string
213
- end
214
- end
215
- ```
216
-
217
- ### Testing Requirements
218
-
219
- #### 1. Add Test Cases
220
- **File**: `spec/concerns/apis/notification_api_spec.rb`
221
-
222
- Add test cases similar to the `destroy_all_of` tests:
223
-
224
- ```ruby
225
- context 'with ids options' do
226
- it "opens notifications with specified IDs only" do
227
- notification_to_open = @user_1.notifications.first
228
- described_class.open_all_of(@user_1, { ids: [notification_to_open.id] })
229
- expect(@user_1.notifications.unopened_only.count).to eq(1)
230
- expect(@user_1.notifications.opened_only!.count).to eq(1)
231
- expect(@user_1.notifications.opened_only!.first).to eq(notification_to_open)
232
- end
233
-
234
- it "applies other filter options when ids are specified" do
235
- notification_to_open = @user_1.notifications.first
236
- described_class.open_all_of(@user_1, {
237
- ids: [notification_to_open.id],
238
- filtered_by_key: 'non_existent_key'
239
- })
240
- expect(@user_1.notifications.unopened_only.count).to eq(2)
241
- expect(@user_1.notifications.opened_only!.count).to eq(0)
242
- end
243
-
244
- it "only opens unopened notifications even when opened notification IDs are provided" do
245
- # First open one notification
246
- notification_to_open = @user_1.notifications.first
247
- notification_to_open.open!
248
-
249
- # Try to open it again using ids parameter
250
- described_class.open_all_of(@user_1, { ids: [notification_to_open.id] })
251
-
252
- # Should not affect the count since it was already opened
253
- expect(@user_1.notifications.unopened_only.count).to eq(1)
254
- expect(@user_1.notifications.opened_only!.count).to eq(1)
255
- end
256
- end
257
- ```
258
-
259
- #### 2. Update Controller Tests
260
- **File**: `spec/controllers/notifications_api_controller_shared_examples.rb`
261
-
262
- Add test cases for the API controller to ensure the `ids` parameter is properly handled:
263
-
264
- ```ruby
265
- context 'with ids parameter' do
266
- it "opens only specified notifications" do
267
- notification_to_open = @user.notifications.first
268
- post open_all_notification_path(@user), params: { ids: [notification_to_open.id] }
269
- expect(response).to have_http_status(200)
270
- expect(@user.notifications.unopened_only.count).to eq(1)
271
- expect(@user.notifications.opened_only!.count).to eq(1)
272
- end
273
- end
274
- ```
275
-
276
- ### Benefits
277
-
278
- #### 1. Consistency
279
- - Provides consistent API between `open_all_of` and `destroy_all_of` methods
280
- - Both methods now support the same filtering options including `ids`
281
-
282
- #### 2. Flexibility
283
- - Allows precise control over which notifications to open
284
- - Enables batch operations on specific notifications
285
- - Supports complex filtering combinations
286
-
287
- #### 3. Performance
288
- - Efficient database operations using bulk updates
289
- - Reduces the need for multiple individual open operations
290
-
291
- #### 4. User Experience
292
- - Provides the functionality requested in the original issue
293
- - Enables building more sophisticated notification management UIs
294
-
295
- ### Implementation Considerations
296
-
297
- #### 1. Backward Compatibility
298
- - All existing functionality remains unchanged
299
- - New `ids` parameter is optional
300
- - Existing tests should continue to pass
301
-
302
- #### 2. ORM Compatibility
303
- - Uses the same ORM-specific logic as `destroy_all_of`
304
- - Tested across ActiveRecord, Mongoid, and Dynamoid
305
-
306
- #### 3. Security
307
- - ID filtering is applied after target validation
308
- - Only notifications belonging to the specified target can be opened
309
- - Follows existing security patterns
310
-
311
- #### 4. Error Handling
312
- - Invalid IDs are silently ignored (consistent with existing behavior)
313
- - Non-existent notifications don't cause errors
314
- - Maintains existing error handling patterns
315
-
316
- ### Risk Assessment
317
- - **Low Risk**: Follows established patterns from `destroy_all_of`
318
- - **Backward Compatible**: ActiveRecord behavior remains unchanged
319
- - **Well-Tested**: Existing test suite will catch any regressions
320
-
321
- ### Implementation Timeline
322
- 1. **Phase 1**: Update `open_all_of` method with ID filtering logic
323
- 2. **Phase 2**: Add comprehensive test cases
324
- 3. **Phase 3**: Update controller actions and API documentation
325
- 4. **Phase 4**: Update controller tests and integration tests
326
- 5. **Phase 5**: Documentation updates and final testing