[stable rewrite]: fix streamer streaming out announces from a muted thread
[akkoma] / test / notification_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.NotificationTest do
6 use Pleroma.DataCase
7
8 import Pleroma.Factory
9 import Mock
10
11 alias Pleroma.FollowingRelationship
12 alias Pleroma.Notification
13 alias Pleroma.Tests.ObanHelpers
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.Transmogrifier
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.MastodonAPI.NotificationView
18 alias Pleroma.Web.Push
19 alias Pleroma.Web.Streamer
20
21 describe "create_notifications" do
22 test "creates a notification for an emoji reaction" do
23 user = insert(:user)
24 other_user = insert(:user)
25
26 {:ok, activity} = CommonAPI.post(user, %{"status" => "yeah"})
27 {:ok, activity, _object} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
28
29 {:ok, [notification]} = Notification.create_notifications(activity)
30
31 assert notification.user_id == user.id
32 end
33
34 test "notifies someone when they are directly addressed" do
35 user = insert(:user)
36 other_user = insert(:user)
37 third_user = insert(:user)
38
39 {:ok, activity} =
40 CommonAPI.post(user, %{
41 "status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
42 })
43
44 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
45
46 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
47 assert notified_ids == [other_user.id, third_user.id]
48 assert notification.activity_id == activity.id
49 assert other_notification.activity_id == activity.id
50 end
51
52 test "it creates a notification for subscribed users" do
53 user = insert(:user)
54 subscriber = insert(:user)
55
56 User.subscribe(subscriber, user)
57
58 {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
59 {:ok, [notification]} = Notification.create_notifications(status)
60
61 assert notification.user_id == subscriber.id
62 end
63
64 test "does not create a notification for subscribed users if status is a reply" do
65 user = insert(:user)
66 other_user = insert(:user)
67 subscriber = insert(:user)
68
69 User.subscribe(subscriber, other_user)
70
71 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
72
73 {:ok, _reply_activity} =
74 CommonAPI.post(other_user, %{
75 "status" => "test reply",
76 "in_reply_to_status_id" => activity.id
77 })
78
79 user_notifications = Notification.for_user(user)
80 assert length(user_notifications) == 1
81
82 subscriber_notifications = Notification.for_user(subscriber)
83 assert Enum.empty?(subscriber_notifications)
84 end
85 end
86
87 describe "CommonApi.post/2 notification-related functionality" do
88 test_with_mock "creates but does NOT send notification to blocker user",
89 Push,
90 [:passthrough],
91 [] do
92 user = insert(:user)
93 blocker = insert(:user)
94 {:ok, _user_relationship} = User.block(blocker, user)
95
96 {:ok, _activity} = CommonAPI.post(user, %{"status" => "hey @#{blocker.nickname}!"})
97
98 blocker_id = blocker.id
99 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
100 refute called(Push.send(:_))
101 end
102
103 test_with_mock "creates but does NOT send notification to notification-muter user",
104 Push,
105 [:passthrough],
106 [] do
107 user = insert(:user)
108 muter = insert(:user)
109 {:ok, _user_relationships} = User.mute(muter, user)
110
111 {:ok, _activity} = CommonAPI.post(user, %{"status" => "hey @#{muter.nickname}!"})
112
113 muter_id = muter.id
114 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
115 refute called(Push.send(:_))
116 end
117
118 test_with_mock "creates but does NOT send notification to thread-muter user",
119 Push,
120 [:passthrough],
121 [] do
122 user = insert(:user)
123 thread_muter = insert(:user)
124
125 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{thread_muter.nickname}!"})
126
127 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
128
129 {:ok, _same_context_activity} =
130 CommonAPI.post(user, %{
131 "status" => "hey-hey-hey @#{thread_muter.nickname}!",
132 "in_reply_to_status_id" => activity.id
133 })
134
135 [pre_mute_notification, post_mute_notification] =
136 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
137
138 pre_mute_notification_id = pre_mute_notification.id
139 post_mute_notification_id = post_mute_notification.id
140
141 assert called(
142 Push.send(
143 :meck.is(fn
144 %Notification{id: ^pre_mute_notification_id} -> true
145 _ -> false
146 end)
147 )
148 )
149
150 refute called(
151 Push.send(
152 :meck.is(fn
153 %Notification{id: ^post_mute_notification_id} -> true
154 _ -> false
155 end)
156 )
157 )
158 end
159 end
160
161 describe "create_notification" do
162 @tag needs_streamer: true
163 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
164 user = insert(:user)
165 task = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
166 task_user_notification = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
167
168 Streamer.get_topic_and_add_socket("user", %{transport_pid: task.pid, assigns: %{user: user}})
169
170 Streamer.get_topic_and_add_socket("user:notification", %{
171 transport_pid: task_user_notification.pid,
172 assigns: %{user: user}
173 })
174
175 activity = insert(:note_activity)
176
177 notify = Notification.create_notification(activity, user)
178 assert notify.user_id == user.id
179 Task.await(task)
180 Task.await(task_user_notification)
181 end
182
183 test "it creates a notification for user if the user blocks the activity author" do
184 activity = insert(:note_activity)
185 author = User.get_cached_by_ap_id(activity.data["actor"])
186 user = insert(:user)
187 {:ok, _user_relationship} = User.block(user, author)
188
189 assert Notification.create_notification(activity, user)
190 end
191
192 test "it creates a notification for the user if the user mutes the activity author" do
193 muter = insert(:user)
194 muted = insert(:user)
195 {:ok, _} = User.mute(muter, muted)
196 muter = Repo.get(User, muter.id)
197 {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
198
199 assert Notification.create_notification(activity, muter)
200 end
201
202 test "notification created if user is muted without notifications" do
203 muter = insert(:user)
204 muted = insert(:user)
205
206 {:ok, _user_relationships} = User.mute(muter, muted, false)
207
208 {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
209
210 assert Notification.create_notification(activity, muter)
211 end
212
213 test "it creates a notification for an activity from a muted thread" do
214 muter = insert(:user)
215 other_user = insert(:user)
216 {:ok, activity} = CommonAPI.post(muter, %{"status" => "hey"})
217 CommonAPI.add_mute(muter, activity)
218
219 {:ok, activity} =
220 CommonAPI.post(other_user, %{
221 "status" => "Hi @#{muter.nickname}",
222 "in_reply_to_status_id" => activity.id
223 })
224
225 assert Notification.create_notification(activity, muter)
226 end
227
228 test "it disables notifications from followers" do
229 follower = insert(:user)
230
231 followed =
232 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
233
234 User.follow(follower, followed)
235 {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
236 refute Notification.create_notification(activity, followed)
237 end
238
239 test "it disables notifications from non-followers" do
240 follower = insert(:user)
241
242 followed =
243 insert(:user,
244 notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
245 )
246
247 {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
248 refute Notification.create_notification(activity, followed)
249 end
250
251 test "it disables notifications from people the user follows" do
252 follower =
253 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{follows: false})
254
255 followed = insert(:user)
256 User.follow(follower, followed)
257 follower = Repo.get(User, follower.id)
258 {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
259 refute Notification.create_notification(activity, follower)
260 end
261
262 test "it disables notifications from people the user does not follow" do
263 follower =
264 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
265
266 followed = insert(:user)
267 {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
268 refute Notification.create_notification(activity, follower)
269 end
270
271 test "it doesn't create a notification for user if he is the activity author" do
272 activity = insert(:note_activity)
273 author = User.get_cached_by_ap_id(activity.data["actor"])
274
275 refute Notification.create_notification(activity, author)
276 end
277
278 test "it doesn't create duplicate notifications for follow+subscribed users" do
279 user = insert(:user)
280 subscriber = insert(:user)
281
282 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
283 User.subscribe(subscriber, user)
284 {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
285 {:ok, [_notif]} = Notification.create_notifications(status)
286 end
287
288 test "it doesn't create subscription notifications if the recipient cannot see the status" do
289 user = insert(:user)
290 subscriber = insert(:user)
291
292 User.subscribe(subscriber, user)
293
294 {:ok, status} = CommonAPI.post(user, %{"status" => "inwisible", "visibility" => "direct"})
295
296 assert {:ok, []} == Notification.create_notifications(status)
297 end
298 end
299
300 describe "follow / follow_request notifications" do
301 test "it creates `follow` notification for approved Follow activity" do
302 user = insert(:user)
303 followed_user = insert(:user, locked: false)
304
305 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
306 assert FollowingRelationship.following?(user, followed_user)
307 assert [notification] = Notification.for_user(followed_user)
308
309 assert %{type: "follow"} =
310 NotificationView.render("show.json", %{
311 notification: notification,
312 for: followed_user
313 })
314 end
315
316 test "it creates `follow_request` notification for pending Follow activity" do
317 user = insert(:user)
318 followed_user = insert(:user, locked: true)
319
320 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
321 refute FollowingRelationship.following?(user, followed_user)
322 assert [notification] = Notification.for_user(followed_user)
323
324 render_opts = %{notification: notification, for: followed_user}
325 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
326
327 # After request is accepted, the same notification is rendered with type "follow":
328 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
329
330 notification_id = notification.id
331 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
332 assert %{type: "follow"} = NotificationView.render("show.json", render_opts)
333 end
334
335 test "it doesn't create a notification for follow-unfollow-follow chains" do
336 user = insert(:user)
337 followed_user = insert(:user, locked: false)
338
339 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
340 assert FollowingRelationship.following?(user, followed_user)
341 assert [notification] = Notification.for_user(followed_user)
342
343 CommonAPI.unfollow(user, followed_user)
344 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
345
346 notification_id = notification.id
347 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
348 end
349
350 test "dismisses the notification on follow request rejection" do
351 user = insert(:user, locked: true)
352 follower = insert(:user)
353 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
354 assert [notification] = Notification.for_user(user)
355 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
356 assert [] = Notification.for_user(user)
357 end
358 end
359
360 describe "get notification" do
361 test "it gets a notification that belongs to the user" do
362 user = insert(:user)
363 other_user = insert(:user)
364
365 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
366
367 {:ok, [notification]} = Notification.create_notifications(activity)
368 {:ok, notification} = Notification.get(other_user, notification.id)
369
370 assert notification.user_id == other_user.id
371 end
372
373 test "it returns error if the notification doesn't belong to the user" do
374 user = insert(:user)
375 other_user = insert(:user)
376
377 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
378
379 {:ok, [notification]} = Notification.create_notifications(activity)
380 {:error, _notification} = Notification.get(user, notification.id)
381 end
382 end
383
384 describe "dismiss notification" do
385 test "it dismisses a notification that belongs to the user" do
386 user = insert(:user)
387 other_user = insert(:user)
388
389 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
390
391 {:ok, [notification]} = Notification.create_notifications(activity)
392 {:ok, notification} = Notification.dismiss(other_user, notification.id)
393
394 assert notification.user_id == other_user.id
395 end
396
397 test "it returns error if the notification doesn't belong to the user" do
398 user = insert(:user)
399 other_user = insert(:user)
400
401 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
402
403 {:ok, [notification]} = Notification.create_notifications(activity)
404 {:error, _notification} = Notification.dismiss(user, notification.id)
405 end
406 end
407
408 describe "clear notification" do
409 test "it clears all notifications belonging to the user" do
410 user = insert(:user)
411 other_user = insert(:user)
412 third_user = insert(:user)
413
414 {:ok, activity} =
415 CommonAPI.post(user, %{
416 "status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
417 })
418
419 {:ok, _notifs} = Notification.create_notifications(activity)
420
421 {:ok, activity} =
422 CommonAPI.post(user, %{
423 "status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
424 })
425
426 {:ok, _notifs} = Notification.create_notifications(activity)
427 Notification.clear(other_user)
428
429 assert Notification.for_user(other_user) == []
430 assert Notification.for_user(third_user) != []
431 end
432 end
433
434 describe "set_read_up_to()" do
435 test "it sets all notifications as read up to a specified notification ID" do
436 user = insert(:user)
437 other_user = insert(:user)
438
439 {:ok, _activity} =
440 CommonAPI.post(user, %{
441 "status" => "hey @#{other_user.nickname}!"
442 })
443
444 {:ok, _activity} =
445 CommonAPI.post(user, %{
446 "status" => "hey again @#{other_user.nickname}!"
447 })
448
449 [n2, n1] = notifs = Notification.for_user(other_user)
450 assert length(notifs) == 2
451
452 assert n2.id > n1.id
453
454 {:ok, _activity} =
455 CommonAPI.post(user, %{
456 "status" => "hey yet again @#{other_user.nickname}!"
457 })
458
459 Notification.set_read_up_to(other_user, n2.id)
460
461 [n3, n2, n1] = Notification.for_user(other_user)
462
463 assert n1.seen == true
464 assert n2.seen == true
465 assert n3.seen == false
466 end
467 end
468
469 describe "for_user_since/2" do
470 defp days_ago(days) do
471 NaiveDateTime.add(
472 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
473 -days * 60 * 60 * 24,
474 :second
475 )
476 end
477
478 test "Returns recent notifications" do
479 user1 = insert(:user)
480 user2 = insert(:user)
481
482 Enum.each(0..10, fn i ->
483 {:ok, _activity} =
484 CommonAPI.post(user1, %{
485 "status" => "hey ##{i} @#{user2.nickname}!"
486 })
487 end)
488
489 {old, new} = Enum.split(Notification.for_user(user2), 5)
490
491 Enum.each(old, fn notification ->
492 notification
493 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
494 |> Pleroma.Repo.update!()
495 end)
496
497 recent_notifications_ids =
498 user2
499 |> Notification.for_user_since(
500 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
501 )
502 |> Enum.map(& &1.id)
503
504 Enum.each(old, fn %{id: id} ->
505 refute id in recent_notifications_ids
506 end)
507
508 Enum.each(new, fn %{id: id} ->
509 assert id in recent_notifications_ids
510 end)
511 end
512 end
513
514 describe "notification target determination / get_notified_from_activity/2" do
515 test "it sends notifications to addressed users in new messages" do
516 user = insert(:user)
517 other_user = insert(:user)
518
519 {:ok, activity} =
520 CommonAPI.post(user, %{
521 "status" => "hey @#{other_user.nickname}!"
522 })
523
524 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
525
526 assert other_user in enabled_receivers
527 end
528
529 test "it sends notifications to mentioned users in new messages" do
530 user = insert(:user)
531 other_user = insert(:user)
532
533 create_activity = %{
534 "@context" => "https://www.w3.org/ns/activitystreams",
535 "type" => "Create",
536 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
537 "actor" => user.ap_id,
538 "object" => %{
539 "type" => "Note",
540 "content" => "message with a Mention tag, but no explicit tagging",
541 "tag" => [
542 %{
543 "type" => "Mention",
544 "href" => other_user.ap_id,
545 "name" => other_user.nickname
546 }
547 ],
548 "attributedTo" => user.ap_id
549 }
550 }
551
552 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
553
554 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
555
556 assert other_user in enabled_receivers
557 end
558
559 test "it does not send notifications to users who are only cc in new messages" do
560 user = insert(:user)
561 other_user = insert(:user)
562
563 create_activity = %{
564 "@context" => "https://www.w3.org/ns/activitystreams",
565 "type" => "Create",
566 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
567 "cc" => [other_user.ap_id],
568 "actor" => user.ap_id,
569 "object" => %{
570 "type" => "Note",
571 "content" => "hi everyone",
572 "attributedTo" => user.ap_id
573 }
574 }
575
576 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
577
578 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
579
580 assert other_user not in enabled_receivers
581 end
582
583 test "it does not send notification to mentioned users in likes" do
584 user = insert(:user)
585 other_user = insert(:user)
586 third_user = insert(:user)
587
588 {:ok, activity_one} =
589 CommonAPI.post(user, %{
590 "status" => "hey @#{other_user.nickname}!"
591 })
592
593 {:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, third_user)
594
595 {enabled_receivers, _disabled_receivers} =
596 Notification.get_notified_from_activity(activity_two)
597
598 assert other_user not in enabled_receivers
599 end
600
601 test "it does not send notification to mentioned users in announces" do
602 user = insert(:user)
603 other_user = insert(:user)
604 third_user = insert(:user)
605
606 {:ok, activity_one} =
607 CommonAPI.post(user, %{
608 "status" => "hey @#{other_user.nickname}!"
609 })
610
611 {:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user)
612
613 {enabled_receivers, _disabled_receivers} =
614 Notification.get_notified_from_activity(activity_two)
615
616 assert other_user not in enabled_receivers
617 end
618
619 test "it returns blocking recipient in disabled recipients list" do
620 user = insert(:user)
621 other_user = insert(:user)
622 {:ok, _user_relationship} = User.block(other_user, user)
623
624 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
625
626 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
627
628 assert [] == enabled_receivers
629 assert [other_user] == disabled_receivers
630 end
631
632 test "it returns notification-muting recipient in disabled recipients list" do
633 user = insert(:user)
634 other_user = insert(:user)
635 {:ok, _user_relationships} = User.mute(other_user, user)
636
637 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
638
639 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
640
641 assert [] == enabled_receivers
642 assert [other_user] == disabled_receivers
643 end
644
645 test "it returns thread-muting recipient in disabled recipients list" do
646 user = insert(:user)
647 other_user = insert(:user)
648
649 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
650
651 {:ok, _} = CommonAPI.add_mute(other_user, activity)
652
653 {:ok, same_context_activity} =
654 CommonAPI.post(user, %{
655 "status" => "hey-hey-hey @#{other_user.nickname}!",
656 "in_reply_to_status_id" => activity.id
657 })
658
659 {enabled_receivers, disabled_receivers} =
660 Notification.get_notified_from_activity(same_context_activity)
661
662 assert [other_user] == disabled_receivers
663 refute other_user in enabled_receivers
664 end
665 end
666
667 describe "notification lifecycle" do
668 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
669 user = insert(:user)
670 other_user = insert(:user)
671
672 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
673
674 assert Enum.empty?(Notification.for_user(user))
675
676 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
677
678 assert length(Notification.for_user(user)) == 1
679
680 {:ok, _} = CommonAPI.delete(activity.id, user)
681
682 assert Enum.empty?(Notification.for_user(user))
683 end
684
685 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
686 user = insert(:user)
687 other_user = insert(:user)
688
689 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
690
691 assert Enum.empty?(Notification.for_user(user))
692
693 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
694
695 assert length(Notification.for_user(user)) == 1
696
697 {:ok, _, _, _} = CommonAPI.unfavorite(activity.id, other_user)
698
699 assert Enum.empty?(Notification.for_user(user))
700 end
701
702 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
703 user = insert(:user)
704 other_user = insert(:user)
705
706 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
707
708 assert Enum.empty?(Notification.for_user(user))
709
710 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
711
712 assert length(Notification.for_user(user)) == 1
713
714 {:ok, _} = CommonAPI.delete(activity.id, user)
715
716 assert Enum.empty?(Notification.for_user(user))
717 end
718
719 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
720 user = insert(:user)
721 other_user = insert(:user)
722
723 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
724
725 assert Enum.empty?(Notification.for_user(user))
726
727 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
728
729 assert length(Notification.for_user(user)) == 1
730
731 {:ok, _, _} = CommonAPI.unrepeat(activity.id, other_user)
732
733 assert Enum.empty?(Notification.for_user(user))
734 end
735
736 test "liking an activity which is already deleted does not generate a notification" do
737 user = insert(:user)
738 other_user = insert(:user)
739
740 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
741
742 assert Enum.empty?(Notification.for_user(user))
743
744 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
745
746 assert Enum.empty?(Notification.for_user(user))
747
748 {:error, _} = CommonAPI.favorite(activity.id, other_user)
749
750 assert Enum.empty?(Notification.for_user(user))
751 end
752
753 test "repeating an activity which is already deleted does not generate a notification" do
754 user = insert(:user)
755 other_user = insert(:user)
756
757 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
758
759 assert Enum.empty?(Notification.for_user(user))
760
761 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
762
763 assert Enum.empty?(Notification.for_user(user))
764
765 {:error, _} = CommonAPI.repeat(activity.id, other_user)
766
767 assert Enum.empty?(Notification.for_user(user))
768 end
769
770 test "replying to a deleted post without tagging does not generate a notification" do
771 user = insert(:user)
772 other_user = insert(:user)
773
774 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
775 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
776
777 {:ok, _reply_activity} =
778 CommonAPI.post(other_user, %{
779 "status" => "test reply",
780 "in_reply_to_status_id" => activity.id
781 })
782
783 assert Enum.empty?(Notification.for_user(user))
784 end
785
786 test "notifications are deleted if a local user is deleted" do
787 user = insert(:user)
788 other_user = insert(:user)
789
790 {:ok, _activity} =
791 CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}", "visibility" => "direct"})
792
793 refute Enum.empty?(Notification.for_user(other_user))
794
795 {:ok, job} = User.delete(user)
796 ObanHelpers.perform(job)
797
798 assert Enum.empty?(Notification.for_user(other_user))
799 end
800
801 test "notifications are deleted if a remote user is deleted" do
802 remote_user = insert(:user)
803 local_user = insert(:user)
804
805 dm_message = %{
806 "@context" => "https://www.w3.org/ns/activitystreams",
807 "type" => "Create",
808 "actor" => remote_user.ap_id,
809 "id" => remote_user.ap_id <> "/activities/test",
810 "to" => [local_user.ap_id],
811 "cc" => [],
812 "object" => %{
813 "type" => "Note",
814 "content" => "Hello!",
815 "tag" => [
816 %{
817 "type" => "Mention",
818 "href" => local_user.ap_id,
819 "name" => "@#{local_user.nickname}"
820 }
821 ],
822 "to" => [local_user.ap_id],
823 "cc" => [],
824 "attributedTo" => remote_user.ap_id
825 }
826 }
827
828 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
829
830 refute Enum.empty?(Notification.for_user(local_user))
831
832 delete_user_message = %{
833 "@context" => "https://www.w3.org/ns/activitystreams",
834 "id" => remote_user.ap_id <> "/activities/delete",
835 "actor" => remote_user.ap_id,
836 "type" => "Delete",
837 "object" => remote_user.ap_id
838 }
839
840 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
841 ObanHelpers.perform_all()
842
843 assert Enum.empty?(Notification.for_user(local_user))
844 end
845
846 test "move activity generates a notification" do
847 %{ap_id: old_ap_id} = old_user = insert(:user)
848 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
849 follower = insert(:user)
850 other_follower = insert(:user, %{allow_following_move: false})
851
852 User.follow(follower, old_user)
853 User.follow(other_follower, old_user)
854
855 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
856 ObanHelpers.perform_all()
857
858 assert [] = Notification.for_user(follower)
859
860 assert [
861 %{
862 activity: %{
863 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
864 }
865 }
866 ] = Notification.for_user(follower, %{with_move: true})
867
868 assert [] = Notification.for_user(other_follower)
869
870 assert [
871 %{
872 activity: %{
873 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
874 }
875 }
876 ] = Notification.for_user(other_follower, %{with_move: true})
877 end
878 end
879
880 describe "for_user" do
881 test "it returns notifications for muted user without notifications" do
882 user = insert(:user)
883 muted = insert(:user)
884 {:ok, _user_relationships} = User.mute(user, muted, false)
885
886 {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
887
888 assert length(Notification.for_user(user)) == 1
889 end
890
891 test "it doesn't return notifications for muted user with notifications" do
892 user = insert(:user)
893 muted = insert(:user)
894 {:ok, _user_relationships} = User.mute(user, muted)
895
896 {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
897
898 assert Notification.for_user(user) == []
899 end
900
901 test "it doesn't return notifications for blocked user" do
902 user = insert(:user)
903 blocked = insert(:user)
904 {:ok, _user_relationship} = User.block(user, blocked)
905
906 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
907
908 assert Notification.for_user(user) == []
909 end
910
911 test "it doesn't return notifications for blocked domain" do
912 user = insert(:user)
913 blocked = insert(:user, ap_id: "http://some-domain.com")
914 {:ok, user} = User.block_domain(user, "some-domain.com")
915
916 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
917
918 assert Notification.for_user(user) == []
919 end
920
921 test "it doesn't return notifications for muted thread" do
922 user = insert(:user)
923 another_user = insert(:user)
924
925 {:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
926
927 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
928 assert Notification.for_user(user) == []
929 end
930
931 test "it returns notifications from a muted user when with_muted is set" do
932 user = insert(:user)
933 muted = insert(:user)
934 {:ok, _user_relationships} = User.mute(user, muted)
935
936 {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
937
938 assert length(Notification.for_user(user, %{with_muted: true})) == 1
939 end
940
941 test "it doesn't return notifications from a blocked user when with_muted is set" do
942 user = insert(:user)
943 blocked = insert(:user)
944 {:ok, _user_relationship} = User.block(user, blocked)
945
946 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
947
948 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
949 end
950
951 test "it doesn't return notifications from a domain-blocked user when with_muted is set" do
952 user = insert(:user)
953 blocked = insert(:user, ap_id: "http://some-domain.com")
954 {:ok, user} = User.block_domain(user, "some-domain.com")
955
956 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
957
958 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
959 end
960
961 test "it returns notifications from muted threads when with_muted is set" do
962 user = insert(:user)
963 another_user = insert(:user)
964
965 {:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
966
967 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
968 assert length(Notification.for_user(user, %{with_muted: true})) == 1
969 end
970 end
971 end