activity_notification 2.3.2 → 2.4.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.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +9 -36
- data/CHANGELOG.md +26 -1
- data/Gemfile +1 -1
- data/README.md +9 -1
- data/activity_notification.gemspec +5 -5
- data/ai-curated-specs/issues/172/design.md +220 -0
- data/ai-curated-specs/issues/172/tasks.md +326 -0
- data/ai-curated-specs/issues/188/design.md +227 -0
- data/ai-curated-specs/issues/188/requirements.md +78 -0
- data/ai-curated-specs/issues/188/tasks.md +203 -0
- data/ai-curated-specs/issues/188/upstream-contributions.md +592 -0
- data/ai-curated-specs/issues/50/design.md +235 -0
- data/ai-curated-specs/issues/50/requirements.md +49 -0
- data/ai-curated-specs/issues/50/tasks.md +232 -0
- data/app/controllers/activity_notification/notifications_api_controller.rb +22 -0
- data/app/controllers/activity_notification/notifications_controller.rb +27 -1
- data/app/mailers/activity_notification/mailer.rb +2 -2
- data/app/views/activity_notification/notifications/default/_index.html.erb +6 -1
- data/app/views/activity_notification/notifications/default/destroy_all.js.erb +6 -0
- data/docs/Setup.md +43 -6
- data/gemfiles/Gemfile.rails-7.0 +2 -0
- data/gemfiles/Gemfile.rails-7.2 +0 -2
- data/gemfiles/Gemfile.rails-8.0 +24 -0
- data/lib/activity_notification/apis/notification_api.rb +51 -2
- data/lib/activity_notification/controllers/concerns/swagger/notifications_api.rb +59 -0
- data/lib/activity_notification/helpers/view_helpers.rb +28 -0
- data/lib/activity_notification/mailers/helpers.rb +14 -7
- data/lib/activity_notification/models/concerns/target.rb +16 -0
- data/lib/activity_notification/models.rb +1 -1
- data/lib/activity_notification/notification_resilience.rb +115 -0
- data/lib/activity_notification/orm/dynamoid/extension.rb +4 -87
- data/lib/activity_notification/orm/dynamoid/notification.rb +19 -2
- data/lib/activity_notification/orm/dynamoid.rb +42 -6
- data/lib/activity_notification/rails/routes.rb +3 -2
- data/lib/activity_notification/version.rb +1 -1
- data/lib/activity_notification.rb +1 -0
- data/lib/generators/templates/controllers/notifications_api_controller.rb +5 -0
- data/lib/generators/templates/controllers/notifications_api_with_devise_controller.rb +5 -0
- data/lib/generators/templates/controllers/notifications_controller.rb +5 -0
- data/lib/generators/templates/controllers/notifications_with_devise_controller.rb +5 -0
- data/spec/concerns/apis/notification_api_spec.rb +161 -5
- data/spec/concerns/models/target_spec.rb +7 -0
- data/spec/controllers/controller_spec_utility.rb +1 -1
- data/spec/controllers/notifications_api_controller_shared_examples.rb +113 -0
- data/spec/controllers/notifications_controller_shared_examples.rb +150 -0
- data/spec/helpers/view_helpers_spec.rb +14 -0
- data/spec/jobs/notification_resilience_job_spec.rb +167 -0
- data/spec/mailers/notification_resilience_spec.rb +263 -0
- data/spec/models/notification_spec.rb +1 -1
- data/spec/models/subscription_spec.rb +1 -1
- data/spec/rails_app/app/helpers/devise_helper.rb +2 -0
- data/spec/rails_app/config/application.rb +1 -0
- data/spec/rails_app/config/initializers/zeitwerk.rb +10 -0
- metadata +67 -53
@@ -98,7 +98,15 @@ module ActivityNotification
|
|
98
98
|
["#{attribute}_key".to_sym, value.nil? ? nil : "#{value.class.name}#{ActivityNotification.config.composite_key_delimiter}#{value.id}"] :
|
99
99
|
[attribute, value]
|
100
100
|
}.to_h
|
101
|
-
|
101
|
+
|
102
|
+
# Use update_attributes if available, otherwise use the manual approach
|
103
|
+
if respond_to?(:update_attributes)
|
104
|
+
update_attributes(attributes_with_association)
|
105
|
+
else
|
106
|
+
# Manual update for models that don't have update_attributes
|
107
|
+
attributes_with_association.each { |attribute, value| write_attribute(attribute, value) }
|
108
|
+
save
|
109
|
+
end
|
102
110
|
end
|
103
111
|
end
|
104
112
|
end
|
@@ -179,10 +187,12 @@ module Dynamoid # :nodoc: all
|
|
179
187
|
# Selects filtered notifications or subscriptions by association type.
|
180
188
|
# @scope class
|
181
189
|
# @param [String] name Association name
|
182
|
-
# @param [Object] type Association type
|
190
|
+
# @param [Object] type Association type (can be class name string or object instance)
|
183
191
|
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications or subscriptions
|
184
192
|
def filtered_by_association_type(name, type)
|
185
|
-
|
193
|
+
# Handle both string class names and object instances
|
194
|
+
type_name = type.is_a?(String) ? type : type.class.name
|
195
|
+
where("#{name}_key.begins_with" => "#{type_name}#{ActivityNotification.config.composite_key_delimiter}")
|
186
196
|
end
|
187
197
|
|
188
198
|
# Selects filtered notifications or subscriptions by association type and id.
|
@@ -391,14 +401,32 @@ module Dynamoid # :nodoc: all
|
|
391
401
|
# @scope class
|
392
402
|
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
393
403
|
def group_members_only
|
394
|
-
|
404
|
+
# Create a new chain to avoid state issues
|
405
|
+
new_chain = @source.where('group_owner_id.not_null': true)
|
406
|
+
# Apply existing conditions from current chain
|
407
|
+
if instance_variable_defined?(:@where_conditions) && @where_conditions
|
408
|
+
@where_conditions.instance_variable_get(:@hash_conditions).each do |condition|
|
409
|
+
# Skip conflicting group_owner_id conditions
|
410
|
+
next if condition.key?(:"group_owner_id.null") || condition.key?(:"group_owner_id.not_null")
|
411
|
+
new_chain = new_chain.where(condition)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
new_chain
|
395
415
|
end
|
396
416
|
|
397
417
|
# Selects unopened notifications only.
|
398
418
|
# @scope class
|
399
419
|
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
400
420
|
def unopened_only
|
401
|
-
|
421
|
+
# Create a new chain to avoid state issues
|
422
|
+
new_chain = @source.where('opened_at.null': true)
|
423
|
+
# Apply existing conditions from current chain
|
424
|
+
if instance_variable_defined?(:@where_conditions) && @where_conditions
|
425
|
+
@where_conditions.instance_variable_get(:@hash_conditions).each do |condition|
|
426
|
+
new_chain = new_chain.where(condition)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
new_chain
|
402
430
|
end
|
403
431
|
|
404
432
|
# Selects opened notifications only without limit.
|
@@ -406,7 +434,15 @@ module Dynamoid # :nodoc: all
|
|
406
434
|
# @scope class
|
407
435
|
# @return [Dynamoid::Criteria::Chain] Database query of filtered notifications
|
408
436
|
def opened_only!
|
409
|
-
|
437
|
+
# Create a new chain to avoid state issues
|
438
|
+
new_chain = @source.where('opened_at.not_null': true)
|
439
|
+
# Apply existing conditions from current chain
|
440
|
+
if instance_variable_defined?(:@where_conditions) && @where_conditions
|
441
|
+
@where_conditions.instance_variable_get(:@hash_conditions).each do |condition|
|
442
|
+
new_chain = new_chain.where(condition)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
new_chain
|
410
446
|
end
|
411
447
|
|
412
448
|
# Selects opened notifications only with limit.
|
@@ -153,7 +153,7 @@ module ActionDispatch::Routing
|
|
153
153
|
if options[:with_devise].present? && options[:devise_default_routes].present?
|
154
154
|
create_notification_routes options, resources_options
|
155
155
|
else
|
156
|
-
self.resources target, only:
|
156
|
+
self.resources target, only: [] do
|
157
157
|
create_notification_routes options, resources_options
|
158
158
|
end
|
159
159
|
end
|
@@ -348,7 +348,7 @@ module ActionDispatch::Routing
|
|
348
348
|
if options[:with_devise].present? && options[:devise_default_routes].present?
|
349
349
|
create_subscription_routes options, resources_options
|
350
350
|
else
|
351
|
-
self.resources target, only:
|
351
|
+
self.resources target, only: [] do
|
352
352
|
create_subscription_routes options, resources_options
|
353
353
|
end
|
354
354
|
end
|
@@ -414,6 +414,7 @@ module ActionDispatch::Routing
|
|
414
414
|
self.resources options[:model], resources_options do
|
415
415
|
collection do
|
416
416
|
post :open_all unless ignore_path?(:open_all, options)
|
417
|
+
post :destroy_all unless ignore_path?(:destroy_all, options)
|
417
418
|
end
|
418
419
|
member do
|
419
420
|
get :move unless ignore_path?(:move, options)
|
@@ -9,6 +9,11 @@ class <%= @target_prefix %>NotificationsController < ActivityNotification::Notif
|
|
9
9
|
# super
|
10
10
|
# end
|
11
11
|
|
12
|
+
# POST /:target_type/:target_id/notifications/destroy_all
|
13
|
+
# def destroy_all
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
|
12
17
|
# GET /:target_type/:target_id/notifications/:id
|
13
18
|
# def show
|
14
19
|
# super
|
@@ -9,6 +9,11 @@ class <%= @target_prefix %>NotificationsWithDeviseController < ActivityNotificat
|
|
9
9
|
# super
|
10
10
|
# end
|
11
11
|
|
12
|
+
# POST /:target_type/:target_id/notifications/destroy_all
|
13
|
+
# def destroy_all
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
|
12
17
|
# GET /:target_type/:target_id/notifications/:id
|
13
18
|
# def show
|
14
19
|
# super
|
@@ -9,6 +9,11 @@ class <%= @target_prefix %>NotificationsController < ActivityNotification::Notif
|
|
9
9
|
# super
|
10
10
|
# end
|
11
11
|
|
12
|
+
# POST /:target_type/:target_id/notifications/destroy_all
|
13
|
+
# def destroy_all
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
|
12
17
|
# GET /:target_type/:target_id/notifications/:id
|
13
18
|
# def show
|
14
19
|
# super
|
@@ -9,6 +9,11 @@ class <%= @target_prefix %>NotificationsWithDeviseController < ActivityNotificat
|
|
9
9
|
# super
|
10
10
|
# end
|
11
11
|
|
12
|
+
# POST /:target_type/:target_id/notifications/destroy_all
|
13
|
+
# def destroy_all
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
|
12
17
|
# GET /:target_type/:target_id/notifications/:id
|
13
18
|
# def show
|
14
19
|
# super
|
@@ -54,7 +54,7 @@ shared_examples_for :notification_api do
|
|
54
54
|
expect(ActivityNotification::Mailer.deliveries.first.to[0]).to eq(@author_user.email)
|
55
55
|
expect(ActivityNotification::Mailer.deliveries.last.to[0]).to eq(@user_1.email)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
it "sends notification email with active job queue" do
|
59
59
|
expect {
|
60
60
|
described_class.notify(:users, @comment_2)
|
@@ -318,7 +318,7 @@ shared_examples_for :notification_api do
|
|
318
318
|
|
319
319
|
context "with options" do
|
320
320
|
context "as default" do
|
321
|
-
let(:created_notification) {
|
321
|
+
let(:created_notification) {
|
322
322
|
described_class.notify_to(@user_1, @comment_2)
|
323
323
|
@user_1.notifications.latest
|
324
324
|
}
|
@@ -360,7 +360,7 @@ shared_examples_for :notification_api do
|
|
360
360
|
end
|
361
361
|
|
362
362
|
context "as specified default value" do
|
363
|
-
let(:created_notification) {
|
363
|
+
let(:created_notification) {
|
364
364
|
described_class.notify_to(@user_1, @comment_2)
|
365
365
|
}
|
366
366
|
|
@@ -382,7 +382,7 @@ shared_examples_for :notification_api do
|
|
382
382
|
end
|
383
383
|
|
384
384
|
context "as api options" do
|
385
|
-
let(:created_notification) {
|
385
|
+
let(:created_notification) {
|
386
386
|
described_class.notify_to(
|
387
387
|
@user_1, @comment_2,
|
388
388
|
key: 'custom_test_key',
|
@@ -592,6 +592,131 @@ shared_examples_for :notification_api do
|
|
592
592
|
expect(@user_1.notifications.opened_only!.count).to eq(1)
|
593
593
|
end
|
594
594
|
end
|
595
|
+
|
596
|
+
context 'with ids options' do
|
597
|
+
it "opens notifications with specified IDs only" do
|
598
|
+
notification_to_open = @user_1.notifications.first
|
599
|
+
described_class.open_all_of(@user_1, { ids: [notification_to_open.id] })
|
600
|
+
expect(@user_1.notifications.unopened_only.count).to eq(1)
|
601
|
+
expect(@user_1.notifications.opened_only!.count).to eq(1)
|
602
|
+
expect(@user_1.notifications.opened_only!.first).to eq(notification_to_open)
|
603
|
+
end
|
604
|
+
|
605
|
+
it "applies other filter options when ids are specified" do
|
606
|
+
notification_to_open = @user_1.notifications.first
|
607
|
+
described_class.open_all_of(@user_1, {
|
608
|
+
ids: [notification_to_open.id],
|
609
|
+
filtered_by_key: 'non_existent_key'
|
610
|
+
})
|
611
|
+
expect(@user_1.notifications.unopened_only.count).to eq(2)
|
612
|
+
expect(@user_1.notifications.opened_only!.count).to eq(0)
|
613
|
+
end
|
614
|
+
|
615
|
+
it "only opens unopened notifications even when opened notification IDs are provided" do
|
616
|
+
# First open one notification
|
617
|
+
notification_to_open = @user_1.notifications.first
|
618
|
+
notification_to_open.open!
|
619
|
+
|
620
|
+
# Try to open it again using ids parameter
|
621
|
+
described_class.open_all_of(@user_1, { ids: [notification_to_open.id] })
|
622
|
+
|
623
|
+
# Should not affect the count since it was already opened
|
624
|
+
expect(@user_1.notifications.unopened_only.count).to eq(1)
|
625
|
+
expect(@user_1.notifications.opened_only!.count).to eq(1)
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
describe ".destroy_all_of" do
|
631
|
+
before do
|
632
|
+
described_class.notify_to(@user_1, @article, group: @article, key: 'key.1')
|
633
|
+
described_class.notify_to(@user_1, @comment_2, group: @comment_2, key: 'key.2')
|
634
|
+
expect(@user_1.notifications.count).to eq(2)
|
635
|
+
expect(@user_2.notifications.count).to eq(0)
|
636
|
+
end
|
637
|
+
|
638
|
+
it "returns array of destroyed notification records" do
|
639
|
+
destroyed_notifications = described_class.destroy_all_of(@user_1)
|
640
|
+
expect(destroyed_notifications).to be_a Array
|
641
|
+
expect(destroyed_notifications.size).to eq(2)
|
642
|
+
end
|
643
|
+
|
644
|
+
it "destroys all notifications of the target" do
|
645
|
+
described_class.destroy_all_of(@user_1)
|
646
|
+
expect(@user_1.notifications.count).to eq(0)
|
647
|
+
end
|
648
|
+
|
649
|
+
it "does not destroy any notifications of the other targets" do
|
650
|
+
described_class.destroy_all_of(@user_2)
|
651
|
+
expect(@user_1.notifications.count).to eq(2)
|
652
|
+
expect(@user_2.notifications.count).to eq(0)
|
653
|
+
end
|
654
|
+
|
655
|
+
context 'with filtered_by_type options' do
|
656
|
+
it "destroys filtered notifications only" do
|
657
|
+
described_class.destroy_all_of(@user_1, { filtered_by_type: @comment_2.to_class_name })
|
658
|
+
expect(@user_1.notifications.count).to eq(1)
|
659
|
+
expect(@user_1.notifications.first.notifiable).to eq(@article)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
context 'with filtered_by_group options' do
|
664
|
+
it "destroys filtered notifications only" do
|
665
|
+
described_class.destroy_all_of(@user_1, { filtered_by_group: @comment_2 })
|
666
|
+
expect(@user_1.notifications.count).to eq(1)
|
667
|
+
expect(@user_1.notifications.first.notifiable).to eq(@article)
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
context 'with filtered_by_group_type and :filtered_by_group_id options' do
|
672
|
+
it "destroys filtered notifications only" do
|
673
|
+
described_class.destroy_all_of(@user_1, { filtered_by_group_type: 'Comment', filtered_by_group_id: @comment_2.id.to_s })
|
674
|
+
expect(@user_1.notifications.count).to eq(1)
|
675
|
+
expect(@user_1.notifications.first.notifiable).to eq(@article)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
context 'with filtered_by_key options' do
|
680
|
+
it "destroys filtered notifications only" do
|
681
|
+
described_class.destroy_all_of(@user_1, { filtered_by_key: 'key.2' })
|
682
|
+
expect(@user_1.notifications.count).to eq(1)
|
683
|
+
expect(@user_1.notifications.first.notifiable).to eq(@article)
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
context 'with later_than options' do
|
688
|
+
it "destroys filtered notifications only" do
|
689
|
+
described_class.destroy_all_of(@user_1, { later_than: (@user_1.notifications.earliest.created_at.in_time_zone + 0.001).iso8601(3) })
|
690
|
+
expect(@user_1.notifications.count).to eq(1)
|
691
|
+
expect(@user_1.notifications.first).to eq(@user_1.notifications.earliest)
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
context 'with earlier_than options' do
|
696
|
+
it "destroys filtered notifications only" do
|
697
|
+
described_class.destroy_all_of(@user_1, { earlier_than: @user_1.notifications.latest.created_at.iso8601(3) })
|
698
|
+
expect(@user_1.notifications.count).to eq(1)
|
699
|
+
expect(@user_1.notifications.first).to eq(@user_1.notifications.latest)
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
context 'with ids options' do
|
704
|
+
it "destroys notifications with specified IDs only" do
|
705
|
+
notification_to_destroy = @user_1.notifications.first
|
706
|
+
described_class.destroy_all_of(@user_1, { ids: [notification_to_destroy.id] })
|
707
|
+
expect(@user_1.notifications.count).to eq(1)
|
708
|
+
expect(@user_1.notifications.first).not_to eq(notification_to_destroy)
|
709
|
+
end
|
710
|
+
|
711
|
+
it "applies other filter options when ids are specified" do
|
712
|
+
notification_to_destroy = @user_1.notifications.first
|
713
|
+
described_class.destroy_all_of(@user_1, {
|
714
|
+
ids: [notification_to_destroy.id],
|
715
|
+
filtered_by_key: 'non_existent_key'
|
716
|
+
})
|
717
|
+
expect(@user_1.notifications.count).to eq(2)
|
718
|
+
end
|
719
|
+
end
|
595
720
|
end
|
596
721
|
|
597
722
|
describe ".group_member_exists?" do
|
@@ -817,6 +942,37 @@ shared_examples_for :notification_api do
|
|
817
942
|
expect(test_instance.open!(with_members: false)).to eq(1)
|
818
943
|
end
|
819
944
|
end
|
945
|
+
|
946
|
+
context "when the associated notifiable record has been deleted" do
|
947
|
+
let(:notifiable_id) { test_instance.notifiable.id }
|
948
|
+
|
949
|
+
before do
|
950
|
+
notifiable_class.where(id: notifiable_id).delete_all
|
951
|
+
test_instance.reload
|
952
|
+
end
|
953
|
+
|
954
|
+
it "ensures the notifiable is gone and the notification is still persisted" do
|
955
|
+
expect(notifiable_class.exists?(notifiable_id)).to be_falsey
|
956
|
+
expect(test_instance).to be_persisted
|
957
|
+
end
|
958
|
+
|
959
|
+
if ActivityNotification.config.orm == :active_record
|
960
|
+
it "does not open the notification without skip_validation option when using ActiveRecord" do
|
961
|
+
test_instance.open!
|
962
|
+
expect(test_instance.reload.opened?).to be_falsey
|
963
|
+
end
|
964
|
+
else
|
965
|
+
it "opens the notification without skip_validation option when using Mongoid or Dynamoid" do
|
966
|
+
test_instance.open!
|
967
|
+
expect(test_instance.reload.opened?).to be_truthy
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
it "opens the notification when skip_validation is true" do
|
972
|
+
test_instance.open!(skip_validation: true)
|
973
|
+
expect(test_instance.reload.opened?).to be_truthy
|
974
|
+
end
|
975
|
+
end
|
820
976
|
end
|
821
977
|
|
822
978
|
describe "#unopened?" do
|
@@ -833,7 +989,7 @@ shared_examples_for :notification_api do
|
|
833
989
|
end
|
834
990
|
end
|
835
991
|
end
|
836
|
-
|
992
|
+
|
837
993
|
describe "#opened?" do
|
838
994
|
context "when opened_at is blank" do
|
839
995
|
it "returns false" do
|
@@ -935,6 +935,13 @@ shared_examples_for :target do
|
|
935
935
|
end
|
936
936
|
end
|
937
937
|
|
938
|
+
describe "#destroy_all_notifications" do
|
939
|
+
it "is an alias of ActivityNotification::Notification.destroy_all_of" do
|
940
|
+
expect(ActivityNotification::Notification).to receive(:destroy_all_of)
|
941
|
+
test_instance.destroy_all_notifications
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
938
945
|
|
939
946
|
# Methods to be overridden
|
940
947
|
|
@@ -275,6 +275,112 @@ shared_examples_for :notifications_api_controller do
|
|
275
275
|
expect(@notification_2.reload.opened?).to be_truthy
|
276
276
|
end
|
277
277
|
end
|
278
|
+
|
279
|
+
context 'with ids parameter' do
|
280
|
+
it "opens only specified notifications" do
|
281
|
+
post_with_compatibility :open_all, target_params.merge({ typed_target_param => test_target, ids: [@notification_1.id] }), valid_session
|
282
|
+
expect(@notification_1.reload.opened?).to be_truthy
|
283
|
+
expect(@notification_2.reload.opened?).to be_falsey
|
284
|
+
end
|
285
|
+
|
286
|
+
it "applies other filter options when ids are specified" do
|
287
|
+
post_with_compatibility :open_all, target_params.merge({
|
288
|
+
typed_target_param => test_target,
|
289
|
+
ids: [@notification_1.id],
|
290
|
+
filtered_by_key: 'non_existent_key'
|
291
|
+
}), valid_session
|
292
|
+
expect(@notification_1.reload.opened?).to be_falsey
|
293
|
+
expect(@notification_2.reload.opened?).to be_falsey
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe "POST #destroy_all" do
|
300
|
+
context "http POST request" do
|
301
|
+
before do
|
302
|
+
@notification = create(:notification, target: test_target)
|
303
|
+
expect(test_target.notifications.count).to eq(1)
|
304
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target }), valid_session
|
305
|
+
end
|
306
|
+
|
307
|
+
it "returns 200 as http status code" do
|
308
|
+
expect(response.status).to eq(200)
|
309
|
+
end
|
310
|
+
|
311
|
+
it "destroys all notifications of the target" do
|
312
|
+
expect(test_target.notifications.count).to eq(0)
|
313
|
+
end
|
314
|
+
|
315
|
+
it "returns JSON response" do
|
316
|
+
expect(response_json["count"]).to eq(1)
|
317
|
+
assert_json_with_object_array(response_json["notifications"], [@notification])
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
context "with filter request parameters" do
|
322
|
+
before do
|
323
|
+
@target_1, @notifiable_1, @group_1, @key_1 = create(:confirmed_user), create(:article), nil, "key.1"
|
324
|
+
@target_2, @notifiable_2, @group_2, @key_2 = create(:confirmed_user), create(:comment), @notifiable_1, "key.2"
|
325
|
+
@notification_1 = create(:notification, target: test_target, notifiable: @notifiable_1, group: @group_1, key: @key_1)
|
326
|
+
@notification_2 = create(:notification, target: test_target, notifiable: @notifiable_2, group: @group_2, key: @key_2, created_at: @notification_1.created_at + 10.second)
|
327
|
+
expect(test_target.notifications.count).to eq(2)
|
328
|
+
end
|
329
|
+
|
330
|
+
context "with filtered_by_type request parameters" do
|
331
|
+
it "destroys filtered notifications only" do
|
332
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target, 'filtered_by_type' => @notifiable_2.to_class_name }), valid_session
|
333
|
+
expect(test_target.notifications.count).to eq(1)
|
334
|
+
expect(test_target.notifications.first).to eq(@notification_1)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
context 'with filtered_by_group_type and :filtered_by_group_id request parameters' do
|
339
|
+
it "destroys filtered notifications only" do
|
340
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target, 'filtered_by_group_type' => 'Article', 'filtered_by_group_id' => @group_2.id.to_s }), valid_session
|
341
|
+
expect(test_target.notifications.count).to eq(1)
|
342
|
+
expect(test_target.notifications.first).to eq(@notification_1)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context 'with filtered_by_key request parameters' do
|
347
|
+
it "destroys filtered notifications only" do
|
348
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target, 'filtered_by_key' => 'key.2' }), valid_session
|
349
|
+
expect(test_target.notifications.count).to eq(1)
|
350
|
+
expect(test_target.notifications.first).to eq(@notification_1)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
context 'with later_than request parameters' do
|
355
|
+
it "destroys filtered notifications only" do
|
356
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target, 'later_than' => (@notification_1.created_at.in_time_zone + 5.second).iso8601(3) }), valid_session
|
357
|
+
expect(test_target.notifications.count).to eq(1)
|
358
|
+
expect(test_target.notifications.first).to eq(@notification_1)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
context 'with earlier_than request parameters' do
|
363
|
+
it "destroys filtered notifications only" do
|
364
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target, 'earlier_than' => (@notification_2.created_at.in_time_zone - 5.second).iso8601(3) }), valid_session
|
365
|
+
expect(test_target.notifications.count).to eq(1)
|
366
|
+
expect(test_target.notifications.first).to eq(@notification_2)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
context "with ids request parameters" do
|
371
|
+
it "destroys notifications with specified IDs only" do
|
372
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target, 'ids' => [@notification_2.id.to_s] }), valid_session
|
373
|
+
expect(test_target.notifications.count).to eq(1)
|
374
|
+
expect(test_target.notifications.first).to eq(@notification_1)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context "with no filter request parameters" do
|
379
|
+
it "destroys all notifications of the target" do
|
380
|
+
post_with_compatibility :destroy_all, target_params.merge({ typed_target_param => test_target}), valid_session
|
381
|
+
expect(test_target.notifications.count).to eq(0)
|
382
|
+
end
|
383
|
+
end
|
278
384
|
end
|
279
385
|
end
|
280
386
|
|
@@ -466,6 +572,13 @@ shared_examples_for :notifications_api_request do
|
|
466
572
|
end
|
467
573
|
end
|
468
574
|
|
575
|
+
describe "POST /{target_type}/{target_id}/notifications/destroy_all", type: :request do
|
576
|
+
it "returns response as API references" do
|
577
|
+
post_with_compatibility "#{api_path}/notifications/destroy_all", headers: @headers
|
578
|
+
assert_all_schema_confirm(response, 200)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
469
582
|
describe "GET /{target_type}/{target_id}/notifications/{id}", type: :request do
|
470
583
|
it "returns response as API references" do
|
471
584
|
get_with_compatibility "#{api_path}/notifications/#{@notification.id}", headers: @headers
|