1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.NotificationTest do
11 alias Pleroma.FollowingRelationship
12 alias Pleroma.Notification
14 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.ActivityPub.Builder
18 alias Pleroma.Web.ActivityPub.Transmogrifier
19 alias Pleroma.Web.CommonAPI
20 alias Pleroma.Web.MastodonAPI.NotificationView
21 alias Pleroma.Web.Push
22 alias Pleroma.Web.Streamer
24 describe "create_notifications" do
25 test "never returns nil" do
27 other_user = insert(:user, %{invisible: true})
29 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
30 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
32 refute {:ok, [nil]} == Notification.create_notifications(activity)
35 test "creates a notification for an emoji reaction" do
37 other_user = insert(:user)
39 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
40 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
42 {:ok, [notification]} = Notification.create_notifications(activity)
44 assert notification.user_id == user.id
45 assert notification.type == "pleroma:emoji_reaction"
48 test "notifies someone when they are directly addressed" do
50 other_user = insert(:user)
51 third_user = insert(:user)
54 CommonAPI.post(user, %{
55 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
58 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
60 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
61 assert notified_ids == [other_user.id, third_user.id]
62 assert notification.activity_id == activity.id
63 assert notification.type == "mention"
64 assert other_notification.activity_id == activity.id
66 assert [%Pleroma.Marker{unread_count: 2}] =
67 Pleroma.Marker.get_markers(other_user, ["notifications"])
70 test "it creates a notification for subscribed users" do
72 subscriber = insert(:user)
74 User.subscribe(subscriber, user)
76 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
77 {:ok, [notification]} = Notification.create_notifications(status)
79 assert notification.user_id == subscriber.id
82 test "does not create a notification for subscribed users if status is a reply" do
84 other_user = insert(:user)
85 subscriber = insert(:user)
87 User.subscribe(subscriber, other_user)
89 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
91 {:ok, _reply_activity} =
92 CommonAPI.post(other_user, %{
94 in_reply_to_status_id: activity.id
97 user_notifications = Notification.for_user(user)
98 assert length(user_notifications) == 1
100 subscriber_notifications = Notification.for_user(subscriber)
101 assert Enum.empty?(subscriber_notifications)
105 describe "CommonApi.post/2 notification-related functionality" do
106 test_with_mock "creates but does NOT send notification to blocker user",
111 blocker = insert(:user)
112 {:ok, _user_relationship} = User.block(blocker, user)
114 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
116 blocker_id = blocker.id
117 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
118 refute called(Push.send(:_))
121 test_with_mock "creates but does NOT send notification to notification-muter user",
126 muter = insert(:user)
127 {:ok, _user_relationships} = User.mute(muter, user)
129 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
132 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
133 refute called(Push.send(:_))
136 test_with_mock "creates but does NOT send notification to thread-muter user",
141 thread_muter = insert(:user)
143 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
145 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
147 {:ok, _same_context_activity} =
148 CommonAPI.post(user, %{
149 status: "hey-hey-hey @#{thread_muter.nickname}!",
150 in_reply_to_status_id: activity.id
153 [pre_mute_notification, post_mute_notification] =
154 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
156 pre_mute_notification_id = pre_mute_notification.id
157 post_mute_notification_id = post_mute_notification.id
162 %Notification{id: ^pre_mute_notification_id} -> true
171 %Notification{id: ^post_mute_notification_id} -> true
179 describe "create_notification" do
180 @tag needs_streamer: true
181 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
186 Streamer.get_topic_and_add_socket("user", user)
187 assert_receive {:render_with_user, _, _, _}, 4_000
190 task_user_notification =
192 Streamer.get_topic_and_add_socket("user:notification", user)
193 assert_receive {:render_with_user, _, _, _}, 4_000
196 activity = insert(:note_activity)
198 notify = Notification.create_notification(activity, user)
199 assert notify.user_id == user.id
201 Task.await(task_user_notification)
204 test "it creates a notification for user if the user blocks the activity author" do
205 activity = insert(:note_activity)
206 author = User.get_cached_by_ap_id(activity.data["actor"])
208 {:ok, _user_relationship} = User.block(user, author)
210 assert Notification.create_notification(activity, user)
213 test "it creates a notification for the user if the user mutes the activity author" do
214 muter = insert(:user)
215 muted = insert(:user)
216 {:ok, _} = User.mute(muter, muted)
217 muter = Repo.get(User, muter.id)
218 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
220 assert Notification.create_notification(activity, muter)
223 test "notification created if user is muted without notifications" do
224 muter = insert(:user)
225 muted = insert(:user)
227 {:ok, _user_relationships} = User.mute(muter, muted, false)
229 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
231 assert Notification.create_notification(activity, muter)
234 test "it creates a notification for an activity from a muted thread" do
235 muter = insert(:user)
236 other_user = insert(:user)
237 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
238 CommonAPI.add_mute(muter, activity)
241 CommonAPI.post(other_user, %{
242 status: "Hi @#{muter.nickname}",
243 in_reply_to_status_id: activity.id
246 assert Notification.create_notification(activity, muter)
249 test "it disables notifications from followers" do
250 follower = insert(:user)
253 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
255 User.follow(follower, followed)
256 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
257 refute Notification.create_notification(activity, followed)
260 test "it disables notifications from non-followers" do
261 follower = insert(:user)
265 notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
268 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
269 refute Notification.create_notification(activity, followed)
272 test "it disables notifications from people the user follows" do
274 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{follows: false})
276 followed = insert(:user)
277 User.follow(follower, followed)
278 follower = Repo.get(User, follower.id)
279 {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
280 refute Notification.create_notification(activity, follower)
283 test "it disables notifications from people the user does not follow" do
285 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
287 followed = insert(:user)
288 {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
289 refute Notification.create_notification(activity, follower)
292 test "it doesn't create a notification for user if he is the activity author" do
293 activity = insert(:note_activity)
294 author = User.get_cached_by_ap_id(activity.data["actor"])
296 refute Notification.create_notification(activity, author)
299 test "it doesn't create duplicate notifications for follow+subscribed users" do
301 subscriber = insert(:user)
303 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
304 User.subscribe(subscriber, user)
305 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
306 {:ok, [_notif]} = Notification.create_notifications(status)
309 test "it doesn't create subscription notifications if the recipient cannot see the status" do
311 subscriber = insert(:user)
313 User.subscribe(subscriber, user)
315 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
317 assert {:ok, []} == Notification.create_notifications(status)
320 test "it disables notifications from people who are invisible" do
321 author = insert(:user, invisible: true)
324 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
325 refute Notification.create_notification(status, user)
328 test "it doesn't create notifications if content matches with an irreversible filter" do
330 subscriber = insert(:user)
332 User.subscribe(subscriber, user)
333 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
335 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
337 assert {:ok, []} == Notification.create_notifications(status)
340 test "it creates notifications if content matches with a not irreversible filter" do
342 subscriber = insert(:user)
344 User.subscribe(subscriber, user)
345 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
347 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
348 {:ok, [notification]} = Notification.create_notifications(status)
353 test "it creates notifications when someone likes user's status with a filtered word" do
355 other_user = insert(:user)
356 insert(:filter, user: user, phrase: "tesla", hide: true)
358 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
359 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
361 {:ok, [notification]} = Notification.create_notifications(activity_two)
367 describe "follow / follow_request notifications" do
368 test "it creates `follow` notification for approved Follow activity" do
370 followed_user = insert(:user, locked: false)
372 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
373 assert FollowingRelationship.following?(user, followed_user)
374 assert [notification] = Notification.for_user(followed_user)
376 assert %{type: "follow"} =
377 NotificationView.render("show.json", %{
378 notification: notification,
383 test "it creates `follow_request` notification for pending Follow activity" do
385 followed_user = insert(:user, locked: true)
387 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
388 refute FollowingRelationship.following?(user, followed_user)
389 assert [notification] = Notification.for_user(followed_user)
391 render_opts = %{notification: notification, for: followed_user}
392 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
394 # After request is accepted, the same notification is rendered with type "follow":
395 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
398 Repo.get(Notification, notification.id)
399 |> Repo.preload(:activity)
401 assert %{type: "follow"} =
402 NotificationView.render("show.json", notification: notification, for: followed_user)
405 test "it doesn't create a notification for follow-unfollow-follow chains" do
407 followed_user = insert(:user, locked: false)
409 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
410 assert FollowingRelationship.following?(user, followed_user)
411 assert [notification] = Notification.for_user(followed_user)
413 CommonAPI.unfollow(user, followed_user)
414 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
416 notification_id = notification.id
417 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
420 test "dismisses the notification on follow request rejection" do
421 user = insert(:user, locked: true)
422 follower = insert(:user)
423 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
424 assert [notification] = Notification.for_user(user)
425 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
426 assert [] = Notification.for_user(user)
430 describe "get notification" do
431 test "it gets a notification that belongs to the user" do
433 other_user = insert(:user)
435 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
437 {:ok, [notification]} = Notification.create_notifications(activity)
438 {:ok, notification} = Notification.get(other_user, notification.id)
440 assert notification.user_id == other_user.id
443 test "it returns error if the notification doesn't belong to the user" do
445 other_user = insert(:user)
447 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
449 {:ok, [notification]} = Notification.create_notifications(activity)
450 {:error, _notification} = Notification.get(user, notification.id)
454 describe "dismiss notification" do
455 test "it dismisses a notification that belongs to the user" do
457 other_user = insert(:user)
459 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
461 {:ok, [notification]} = Notification.create_notifications(activity)
462 {:ok, notification} = Notification.dismiss(other_user, notification.id)
464 assert notification.user_id == other_user.id
467 test "it returns error if the notification doesn't belong to the user" do
469 other_user = insert(:user)
471 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
473 {:ok, [notification]} = Notification.create_notifications(activity)
474 {:error, _notification} = Notification.dismiss(user, notification.id)
478 describe "clear notification" do
479 test "it clears all notifications belonging to the user" do
481 other_user = insert(:user)
482 third_user = insert(:user)
485 CommonAPI.post(user, %{
486 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
489 {:ok, _notifs} = Notification.create_notifications(activity)
492 CommonAPI.post(user, %{
493 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
496 {:ok, _notifs} = Notification.create_notifications(activity)
497 Notification.clear(other_user)
499 assert Notification.for_user(other_user) == []
500 assert Notification.for_user(third_user) != []
504 describe "set_read_up_to()" do
505 test "it sets all notifications as read up to a specified notification ID" do
507 other_user = insert(:user)
510 CommonAPI.post(user, %{
511 status: "hey @#{other_user.nickname}!"
515 CommonAPI.post(user, %{
516 status: "hey again @#{other_user.nickname}!"
519 [n2, n1] = Notification.for_user(other_user)
524 CommonAPI.post(user, %{
525 status: "hey yet again @#{other_user.nickname}!"
528 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
530 assert read_notification.activity.object
532 [n3, n2, n1] = Notification.for_user(other_user)
534 assert n1.seen == true
535 assert n2.seen == true
536 assert n3.seen == false
538 assert %Pleroma.Marker{} =
542 user_id: other_user.id,
543 timeline: "notifications"
546 assert m.last_read_id == to_string(n2.id)
550 describe "for_user_since/2" do
551 defp days_ago(days) do
553 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
554 -days * 60 * 60 * 24,
559 test "Returns recent notifications" do
560 user1 = insert(:user)
561 user2 = insert(:user)
563 Enum.each(0..10, fn i ->
565 CommonAPI.post(user1, %{
566 status: "hey ##{i} @#{user2.nickname}!"
570 {old, new} = Enum.split(Notification.for_user(user2), 5)
572 Enum.each(old, fn notification ->
574 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
575 |> Pleroma.Repo.update!()
578 recent_notifications_ids =
580 |> Notification.for_user_since(
581 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
585 Enum.each(old, fn %{id: id} ->
586 refute id in recent_notifications_ids
589 Enum.each(new, fn %{id: id} ->
590 assert id in recent_notifications_ids
595 describe "notification target determination / get_notified_from_activity/2" do
596 test "it sends notifications to addressed users in new messages" do
598 other_user = insert(:user)
601 CommonAPI.post(user, %{
602 status: "hey @#{other_user.nickname}!"
605 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
607 assert other_user in enabled_receivers
610 test "it sends notifications to mentioned users in new messages" do
612 other_user = insert(:user)
615 "@context" => "https://www.w3.org/ns/activitystreams",
617 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
618 "actor" => user.ap_id,
621 "content" => "message with a Mention tag, but no explicit tagging",
625 "href" => other_user.ap_id,
626 "name" => other_user.nickname
629 "attributedTo" => user.ap_id
633 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
635 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
637 assert other_user in enabled_receivers
640 test "it does not send notifications to users who are only cc in new messages" do
642 other_user = insert(:user)
645 "@context" => "https://www.w3.org/ns/activitystreams",
647 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
648 "cc" => [other_user.ap_id],
649 "actor" => user.ap_id,
652 "content" => "hi everyone",
653 "attributedTo" => user.ap_id
657 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
659 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
661 assert other_user not in enabled_receivers
664 test "it does not send notification to mentioned users in likes" do
666 other_user = insert(:user)
667 third_user = insert(:user)
669 {:ok, activity_one} =
670 CommonAPI.post(user, %{
671 status: "hey @#{other_user.nickname}!"
674 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
676 {enabled_receivers, _disabled_receivers} =
677 Notification.get_notified_from_activity(activity_two)
679 assert other_user not in enabled_receivers
682 test "it only notifies the post's author in likes" do
684 other_user = insert(:user)
685 third_user = insert(:user)
687 {:ok, activity_one} =
688 CommonAPI.post(user, %{
689 status: "hey @#{other_user.nickname}!"
692 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
696 |> Map.put("to", [other_user.ap_id | like_data["to"]])
697 |> ActivityPub.persist(local: true)
699 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
701 assert other_user not in enabled_receivers
704 test "it does not send notification to mentioned users in announces" do
706 other_user = insert(:user)
707 third_user = insert(:user)
709 {:ok, activity_one} =
710 CommonAPI.post(user, %{
711 status: "hey @#{other_user.nickname}!"
714 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
716 {enabled_receivers, _disabled_receivers} =
717 Notification.get_notified_from_activity(activity_two)
719 assert other_user not in enabled_receivers
722 test "it returns blocking recipient in disabled recipients list" do
724 other_user = insert(:user)
725 {:ok, _user_relationship} = User.block(other_user, user)
727 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
729 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
731 assert [] == enabled_receivers
732 assert [other_user] == disabled_receivers
735 test "it returns notification-muting recipient in disabled recipients list" do
737 other_user = insert(:user)
738 {:ok, _user_relationships} = User.mute(other_user, user)
740 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
742 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
744 assert [] == enabled_receivers
745 assert [other_user] == disabled_receivers
748 test "it returns thread-muting recipient in disabled recipients list" do
750 other_user = insert(:user)
752 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
754 {:ok, _} = CommonAPI.add_mute(other_user, activity)
756 {:ok, same_context_activity} =
757 CommonAPI.post(user, %{
758 status: "hey-hey-hey @#{other_user.nickname}!",
759 in_reply_to_status_id: activity.id
762 {enabled_receivers, disabled_receivers} =
763 Notification.get_notified_from_activity(same_context_activity)
765 assert [other_user] == disabled_receivers
766 refute other_user in enabled_receivers
769 test "it returns non-following domain-blocking recipient in disabled recipients list" do
770 blocked_domain = "blocked.domain"
771 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
772 other_user = insert(:user)
774 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
776 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
778 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
780 assert [] == enabled_receivers
781 assert [other_user] == disabled_receivers
784 test "it returns following domain-blocking recipient in enabled recipients list" do
785 blocked_domain = "blocked.domain"
786 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
787 other_user = insert(:user)
789 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
790 {:ok, other_user} = User.follow(other_user, user)
792 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
794 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
796 assert [other_user] == enabled_receivers
797 assert [] == disabled_receivers
801 describe "notification lifecycle" do
802 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
804 other_user = insert(:user)
806 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
808 assert Enum.empty?(Notification.for_user(user))
810 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
812 assert length(Notification.for_user(user)) == 1
814 {:ok, _} = CommonAPI.delete(activity.id, user)
816 assert Enum.empty?(Notification.for_user(user))
819 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
821 other_user = insert(:user)
823 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
825 assert Enum.empty?(Notification.for_user(user))
827 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
829 assert length(Notification.for_user(user)) == 1
831 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
833 assert Enum.empty?(Notification.for_user(user))
836 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
838 other_user = insert(:user)
840 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
842 assert Enum.empty?(Notification.for_user(user))
844 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
846 assert length(Notification.for_user(user)) == 1
848 {:ok, _} = CommonAPI.delete(activity.id, user)
850 assert Enum.empty?(Notification.for_user(user))
853 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
855 other_user = insert(:user)
857 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
859 assert Enum.empty?(Notification.for_user(user))
861 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
863 assert length(Notification.for_user(user)) == 1
865 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
867 assert Enum.empty?(Notification.for_user(user))
870 test "liking an activity which is already deleted does not generate a notification" do
872 other_user = insert(:user)
874 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
876 assert Enum.empty?(Notification.for_user(user))
878 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
880 assert Enum.empty?(Notification.for_user(user))
882 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
884 assert Enum.empty?(Notification.for_user(user))
887 test "repeating an activity which is already deleted does not generate a notification" do
889 other_user = insert(:user)
891 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
893 assert Enum.empty?(Notification.for_user(user))
895 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
897 assert Enum.empty?(Notification.for_user(user))
899 {:error, _} = CommonAPI.repeat(activity.id, other_user)
901 assert Enum.empty?(Notification.for_user(user))
904 test "replying to a deleted post without tagging does not generate a notification" do
906 other_user = insert(:user)
908 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
909 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
911 {:ok, _reply_activity} =
912 CommonAPI.post(other_user, %{
913 status: "test reply",
914 in_reply_to_status_id: activity.id
917 assert Enum.empty?(Notification.for_user(user))
920 test "notifications are deleted if a local user is deleted" do
922 other_user = insert(:user)
925 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
927 refute Enum.empty?(Notification.for_user(other_user))
929 {:ok, job} = User.delete(user)
930 ObanHelpers.perform(job)
932 assert Enum.empty?(Notification.for_user(other_user))
935 test "notifications are deleted if a remote user is deleted" do
936 remote_user = insert(:user)
937 local_user = insert(:user)
940 "@context" => "https://www.w3.org/ns/activitystreams",
942 "actor" => remote_user.ap_id,
943 "id" => remote_user.ap_id <> "/activities/test",
944 "to" => [local_user.ap_id],
948 "content" => "Hello!",
952 "href" => local_user.ap_id,
953 "name" => "@#{local_user.nickname}"
956 "to" => [local_user.ap_id],
958 "attributedTo" => remote_user.ap_id
962 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
964 refute Enum.empty?(Notification.for_user(local_user))
966 delete_user_message = %{
967 "@context" => "https://www.w3.org/ns/activitystreams",
968 "id" => remote_user.ap_id <> "/activities/delete",
969 "actor" => remote_user.ap_id,
971 "object" => remote_user.ap_id
974 remote_user_url = remote_user.ap_id
977 %{method: :get, url: ^remote_user_url} ->
978 %Tesla.Env{status: 404, body: ""}
981 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
982 ObanHelpers.perform_all()
984 assert Enum.empty?(Notification.for_user(local_user))
987 @tag capture_log: true
988 test "move activity generates a notification" do
989 %{ap_id: old_ap_id} = old_user = insert(:user)
990 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
991 follower = insert(:user)
992 other_follower = insert(:user, %{allow_following_move: false})
994 User.follow(follower, old_user)
995 User.follow(other_follower, old_user)
997 old_user_url = old_user.ap_id
1000 File.read!("test/fixtures/users_mock/localhost.json")
1001 |> String.replace("{{nickname}}", old_user.nickname)
1005 %{method: :get, url: ^old_user_url} ->
1006 %Tesla.Env{status: 200, body: body}
1009 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1010 ObanHelpers.perform_all()
1015 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1018 ] = Notification.for_user(follower)
1023 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1026 ] = Notification.for_user(other_follower)
1030 describe "for_user" do
1032 user = insert(:user)
1034 {:ok, %{user: user}}
1037 test "it returns notifications for muted user without notifications", %{user: user} do
1038 muted = insert(:user)
1039 {:ok, _user_relationships} = User.mute(user, muted, false)
1041 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1043 [notification] = Notification.for_user(user)
1045 assert notification.activity.object
1048 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1049 muted = insert(:user)
1050 {:ok, _user_relationships} = User.mute(user, muted)
1052 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1054 assert Notification.for_user(user) == []
1057 test "it doesn't return notifications for blocked user", %{user: user} do
1058 blocked = insert(:user)
1059 {:ok, _user_relationship} = User.block(user, blocked)
1061 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1063 assert Notification.for_user(user) == []
1066 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1067 blocked = insert(:user, ap_id: "http://some-domain.com")
1068 {:ok, user} = User.block_domain(user, "some-domain.com")
1070 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1072 assert Notification.for_user(user) == []
1075 test "it returns notifications for domain-blocked but followed user" do
1076 user = insert(:user)
1077 blocked = insert(:user, ap_id: "http://some-domain.com")
1079 {:ok, user} = User.block_domain(user, "some-domain.com")
1080 {:ok, _} = User.follow(user, blocked)
1082 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1084 assert length(Notification.for_user(user)) == 1
1087 test "it doesn't return notifications for muted thread", %{user: user} do
1088 another_user = insert(:user)
1090 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1092 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1093 assert Notification.for_user(user) == []
1096 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1097 muted = insert(:user)
1098 {:ok, _user_relationships} = User.mute(user, muted)
1100 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1102 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1105 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1108 blocked = insert(:user)
1109 {:ok, _user_relationship} = User.block(user, blocked)
1111 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1113 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1116 test "when with_muted is set, " <>
1117 "it doesn't return notifications from a domain-blocked non-followed user",
1119 blocked = insert(:user, ap_id: "http://some-domain.com")
1120 {:ok, user} = User.block_domain(user, "some-domain.com")
1122 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1124 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1127 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1128 another_user = insert(:user)
1130 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1132 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1133 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1136 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1137 insert(:filter, user: user, phrase: "cofe", hide: true)
1138 another_user = insert(:user)
1140 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1142 assert Enum.empty?(Notification.for_user(user))
1145 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1146 insert(:filter, user: user, phrase: "test", hide: false)
1147 another_user = insert(:user)
1149 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1151 assert length(Notification.for_user(user)) == 1
1154 test "it returns notifications about favorites with filtered word", %{user: user} do
1155 insert(:filter, user: user, phrase: "cofe", hide: true)
1156 another_user = insert(:user)
1158 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1159 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1161 assert length(Notification.for_user(user)) == 1