1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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 a report" do
36 reporting_user = insert(:user)
37 reported_user = insert(:user)
38 {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true})
40 {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
42 {:ok, [notification]} = Notification.create_notifications(activity)
44 assert notification.user_id == moderator_user.id
45 assert notification.type == "pleroma:report"
48 test "suppresses notification to reporter if reporter is an admin" do
49 reporting_admin = insert(:user, is_admin: true)
50 reported_user = insert(:user)
51 other_admin = insert(:user, is_admin: true)
53 {:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id})
55 {:ok, [notification]} = Notification.create_notifications(activity)
57 refute notification.user_id == reporting_admin.id
58 assert notification.user_id == other_admin.id
59 assert notification.type == "pleroma:report"
62 test "creates a notification for an emoji reaction" do
64 other_user = insert(:user)
66 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
67 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
69 {:ok, [notification]} = Notification.create_notifications(activity)
71 assert notification.user_id == user.id
72 assert notification.type == "pleroma:emoji_reaction"
75 test "notifies someone when they are directly addressed" do
77 other_user = insert(:user)
78 third_user = insert(:user)
81 CommonAPI.post(user, %{
82 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
85 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
87 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
88 assert notified_ids == [other_user.id, third_user.id]
89 assert notification.activity_id == activity.id
90 assert notification.type == "mention"
91 assert other_notification.activity_id == activity.id
93 assert [%Pleroma.Marker{unread_count: 2}] =
94 Pleroma.Marker.get_markers(other_user, ["notifications"])
97 test "it creates a notification for subscribed users" do
99 subscriber = insert(:user)
101 User.subscribe(subscriber, user)
103 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
104 {:ok, [notification]} = Notification.create_notifications(status)
106 assert notification.user_id == subscriber.id
109 test "does not create a notification for subscribed users if status is a reply" do
111 other_user = insert(:user)
112 subscriber = insert(:user)
114 User.subscribe(subscriber, other_user)
116 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
118 {:ok, _reply_activity} =
119 CommonAPI.post(other_user, %{
120 status: "test reply",
121 in_reply_to_status_id: activity.id
124 user_notifications = Notification.for_user(user)
125 assert length(user_notifications) == 1
127 subscriber_notifications = Notification.for_user(subscriber)
128 assert Enum.empty?(subscriber_notifications)
132 describe "CommonApi.post/2 notification-related functionality" do
133 test_with_mock "creates but does NOT send notification to blocker user",
138 blocker = insert(:user)
139 {:ok, _user_relationship} = User.block(blocker, user)
141 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
143 blocker_id = blocker.id
144 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
145 refute called(Push.send(:_))
148 test_with_mock "creates but does NOT send notification to notification-muter user",
153 muter = insert(:user)
154 {:ok, _user_relationships} = User.mute(muter, user)
156 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
159 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
160 refute called(Push.send(:_))
163 test_with_mock "creates but does NOT send notification to thread-muter user",
168 thread_muter = insert(:user)
170 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
172 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
174 {:ok, _same_context_activity} =
175 CommonAPI.post(user, %{
176 status: "hey-hey-hey @#{thread_muter.nickname}!",
177 in_reply_to_status_id: activity.id
180 [pre_mute_notification, post_mute_notification] =
181 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
183 pre_mute_notification_id = pre_mute_notification.id
184 post_mute_notification_id = post_mute_notification.id
189 %Notification{id: ^pre_mute_notification_id} -> true
198 %Notification{id: ^post_mute_notification_id} -> true
206 describe "create_notification" do
207 @tag needs_streamer: true
208 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
209 %{user: user, token: oauth_token} = oauth_access(["read"])
213 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
214 assert_receive {:render_with_user, _, _, _}, 4_000
217 task_user_notification =
220 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
222 assert_receive {:render_with_user, _, _, _}, 4_000
225 activity = insert(:note_activity)
227 notify = Notification.create_notification(activity, user)
228 assert notify.user_id == user.id
230 Task.await(task_user_notification)
233 test "it creates a notification for user if the user blocks the activity author" do
234 activity = insert(:note_activity)
235 author = User.get_cached_by_ap_id(activity.data["actor"])
237 {:ok, _user_relationship} = User.block(user, author)
239 assert Notification.create_notification(activity, user)
242 test "it creates a notification for the user if the user mutes the activity author" do
243 muter = insert(:user)
244 muted = insert(:user)
245 {:ok, _} = User.mute(muter, muted)
246 muter = Repo.get(User, muter.id)
247 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
249 notification = Notification.create_notification(activity, muter)
251 assert notification.id
252 assert notification.seen
255 test "notification created if user is muted without notifications" do
256 muter = insert(:user)
257 muted = insert(:user)
259 {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
261 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
263 assert Notification.create_notification(activity, muter)
266 test "it creates a notification for an activity from a muted thread" do
267 muter = insert(:user)
268 other_user = insert(:user)
269 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
270 CommonAPI.add_mute(muter, activity)
273 CommonAPI.post(other_user, %{
274 status: "Hi @#{muter.nickname}",
275 in_reply_to_status_id: activity.id
278 notification = Notification.create_notification(activity, muter)
280 assert notification.id
281 assert notification.seen
284 test "it disables notifications from strangers" do
285 follower = insert(:user)
289 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
292 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
293 refute Notification.create_notification(activity, followed)
296 test "it doesn't create a notification for user if he is the activity author" do
297 activity = insert(:note_activity)
298 author = User.get_cached_by_ap_id(activity.data["actor"])
300 refute Notification.create_notification(activity, author)
303 test "it doesn't create duplicate notifications for follow+subscribed users" do
305 subscriber = insert(:user)
307 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
308 User.subscribe(subscriber, user)
309 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
310 {:ok, [_notif]} = Notification.create_notifications(status)
313 test "it doesn't create subscription notifications if the recipient cannot see the status" do
315 subscriber = insert(:user)
317 User.subscribe(subscriber, user)
319 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
321 assert {:ok, []} == Notification.create_notifications(status)
324 test "it disables notifications from people who are invisible" do
325 author = insert(:user, invisible: true)
328 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
329 refute Notification.create_notification(status, user)
332 test "it doesn't create notifications if content matches with an irreversible filter" do
334 subscriber = insert(:user)
336 User.subscribe(subscriber, user)
337 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
339 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
341 assert {:ok, []} == Notification.create_notifications(status)
344 test "it creates notifications if content matches with a not irreversible filter" do
346 subscriber = insert(:user)
348 User.subscribe(subscriber, user)
349 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
351 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
352 {:ok, [notification]} = Notification.create_notifications(status)
355 refute notification.seen
358 test "it creates notifications when someone likes user's status with a filtered word" do
360 other_user = insert(:user)
361 insert(:filter, user: user, phrase: "tesla", hide: true)
363 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
364 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
366 {:ok, [notification]} = Notification.create_notifications(activity_two)
369 refute notification.seen
373 describe "follow / follow_request notifications" do
374 test "it creates `follow` notification for approved Follow activity" do
376 followed_user = insert(:user, is_locked: false)
378 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
379 assert FollowingRelationship.following?(user, followed_user)
380 assert [notification] = Notification.for_user(followed_user)
382 assert %{type: "follow"} =
383 NotificationView.render("show.json", %{
384 notification: notification,
389 test "it creates `follow_request` notification for pending Follow activity" do
391 followed_user = insert(:user, is_locked: true)
393 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
394 refute FollowingRelationship.following?(user, followed_user)
395 assert [notification] = Notification.for_user(followed_user)
397 render_opts = %{notification: notification, for: followed_user}
398 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
400 # After request is accepted, the same notification is rendered with type "follow":
401 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
404 Repo.get(Notification, notification.id)
405 |> Repo.preload(:activity)
407 assert %{type: "follow"} =
408 NotificationView.render("show.json", notification: notification, for: followed_user)
411 test "it doesn't create a notification for follow-unfollow-follow chains" do
413 followed_user = insert(:user, is_locked: false)
415 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
416 assert FollowingRelationship.following?(user, followed_user)
417 assert [notification] = Notification.for_user(followed_user)
419 CommonAPI.unfollow(user, followed_user)
420 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
422 notification_id = notification.id
423 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
426 test "dismisses the notification on follow request rejection" do
427 user = insert(:user, is_locked: true)
428 follower = insert(:user)
429 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
430 assert [_notification] = Notification.for_user(user)
431 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
432 assert [] = Notification.for_user(user)
436 describe "get notification" do
437 test "it gets a notification that belongs to the user" do
439 other_user = insert(:user)
441 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
443 {:ok, [notification]} = Notification.create_notifications(activity)
444 {:ok, notification} = Notification.get(other_user, notification.id)
446 assert notification.user_id == other_user.id
449 test "it returns error if the notification doesn't belong to the user" do
451 other_user = insert(:user)
453 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
455 {:ok, [notification]} = Notification.create_notifications(activity)
456 {:error, _notification} = Notification.get(user, notification.id)
460 describe "dismiss notification" do
461 test "it dismisses a notification that belongs to the user" do
463 other_user = insert(:user)
465 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
467 {:ok, [notification]} = Notification.create_notifications(activity)
468 {:ok, notification} = Notification.dismiss(other_user, notification.id)
470 assert notification.user_id == other_user.id
473 test "it returns error if the notification doesn't belong to the user" do
475 other_user = insert(:user)
477 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
479 {:ok, [notification]} = Notification.create_notifications(activity)
480 {:error, _notification} = Notification.dismiss(user, notification.id)
484 describe "clear notification" do
485 test "it clears all notifications belonging to the user" do
487 other_user = insert(:user)
488 third_user = insert(:user)
491 CommonAPI.post(user, %{
492 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
495 {:ok, _notifs} = Notification.create_notifications(activity)
498 CommonAPI.post(user, %{
499 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
502 {:ok, _notifs} = Notification.create_notifications(activity)
503 Notification.clear(other_user)
505 assert Notification.for_user(other_user) == []
506 assert Notification.for_user(third_user) != []
510 describe "set_read_up_to()" do
511 test "it sets all notifications as read up to a specified notification ID" do
513 other_user = insert(:user)
516 CommonAPI.post(user, %{
517 status: "hey @#{other_user.nickname}!"
521 CommonAPI.post(user, %{
522 status: "hey again @#{other_user.nickname}!"
525 [n2, n1] = Notification.for_user(other_user)
530 CommonAPI.post(user, %{
531 status: "hey yet again @#{other_user.nickname}!"
534 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
536 assert read_notification.activity.object
538 [n3, n2, n1] = Notification.for_user(other_user)
540 assert n1.seen == true
541 assert n2.seen == true
542 assert n3.seen == false
544 assert %Pleroma.Marker{} =
548 user_id: other_user.id,
549 timeline: "notifications"
552 assert m.last_read_id == to_string(n2.id)
556 describe "for_user_since/2" do
557 defp days_ago(days) do
559 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
560 -days * 60 * 60 * 24,
565 test "Returns recent notifications" do
566 user1 = insert(:user)
567 user2 = insert(:user)
569 Enum.each(0..10, fn i ->
571 CommonAPI.post(user1, %{
572 status: "hey ##{i} @#{user2.nickname}!"
576 {old, new} = Enum.split(Notification.for_user(user2), 5)
578 Enum.each(old, fn notification ->
580 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
581 |> Pleroma.Repo.update!()
584 recent_notifications_ids =
586 |> Notification.for_user_since(
587 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
591 Enum.each(old, fn %{id: id} ->
592 refute id in recent_notifications_ids
595 Enum.each(new, fn %{id: id} ->
596 assert id in recent_notifications_ids
601 describe "notification target determination / get_notified_from_activity/2" do
602 test "it sends notifications to addressed users in new messages" do
604 other_user = insert(:user)
607 CommonAPI.post(user, %{
608 status: "hey @#{other_user.nickname}!"
611 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
613 assert other_user in enabled_receivers
616 test "it sends notifications to mentioned users in new messages" do
618 other_user = insert(:user)
621 "@context" => "https://www.w3.org/ns/activitystreams",
623 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
624 "actor" => user.ap_id,
627 "content" => "message with a Mention tag, but no explicit tagging",
631 "href" => other_user.ap_id,
632 "name" => other_user.nickname
635 "attributedTo" => user.ap_id
639 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
641 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
643 assert other_user in enabled_receivers
646 test "it does not send notifications to users who are only cc in new messages" do
648 other_user = insert(:user)
651 "@context" => "https://www.w3.org/ns/activitystreams",
653 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
654 "cc" => [other_user.ap_id],
655 "actor" => user.ap_id,
658 "content" => "hi everyone",
659 "attributedTo" => user.ap_id
663 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
665 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
667 assert other_user not in enabled_receivers
670 test "it does not send notification to mentioned users in likes" do
672 other_user = insert(:user)
673 third_user = insert(:user)
675 {:ok, activity_one} =
676 CommonAPI.post(user, %{
677 status: "hey @#{other_user.nickname}!"
680 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
682 {enabled_receivers, _disabled_receivers} =
683 Notification.get_notified_from_activity(activity_two)
685 assert other_user not in enabled_receivers
688 test "it only notifies the post's author in likes" do
690 other_user = insert(:user)
691 third_user = insert(:user)
693 {:ok, activity_one} =
694 CommonAPI.post(user, %{
695 status: "hey @#{other_user.nickname}!"
698 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
702 |> Map.put("to", [other_user.ap_id | like_data["to"]])
703 |> ActivityPub.persist(local: true)
705 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
707 assert other_user not in enabled_receivers
710 test "it does not send notification to mentioned users in announces" do
712 other_user = insert(:user)
713 third_user = insert(:user)
715 {:ok, activity_one} =
716 CommonAPI.post(user, %{
717 status: "hey @#{other_user.nickname}!"
720 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
722 {enabled_receivers, _disabled_receivers} =
723 Notification.get_notified_from_activity(activity_two)
725 assert other_user not in enabled_receivers
728 test "it returns blocking recipient in disabled recipients list" do
730 other_user = insert(:user)
731 {:ok, _user_relationship} = User.block(other_user, user)
733 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
735 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
737 assert [] == enabled_receivers
738 assert [other_user] == disabled_receivers
741 test "it returns notification-muting recipient in disabled recipients list" do
743 other_user = insert(:user)
744 {:ok, _user_relationships} = User.mute(other_user, user)
746 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
748 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
750 assert [] == enabled_receivers
751 assert [other_user] == disabled_receivers
754 test "it returns thread-muting recipient in disabled recipients list" do
756 other_user = insert(:user)
758 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
760 {:ok, _} = CommonAPI.add_mute(other_user, activity)
762 {:ok, same_context_activity} =
763 CommonAPI.post(user, %{
764 status: "hey-hey-hey @#{other_user.nickname}!",
765 in_reply_to_status_id: activity.id
768 {enabled_receivers, disabled_receivers} =
769 Notification.get_notified_from_activity(same_context_activity)
771 assert [other_user] == disabled_receivers
772 refute other_user in enabled_receivers
775 test "it returns non-following domain-blocking recipient in disabled recipients list" do
776 blocked_domain = "blocked.domain"
777 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
778 other_user = insert(:user)
780 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
782 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
784 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
786 assert [] == enabled_receivers
787 assert [other_user] == disabled_receivers
790 test "it returns following domain-blocking recipient in enabled recipients list" do
791 blocked_domain = "blocked.domain"
792 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
793 other_user = insert(:user)
795 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
796 {:ok, other_user, user} = User.follow(other_user, user)
798 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
800 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
802 assert [other_user] == enabled_receivers
803 assert [] == disabled_receivers
807 describe "notification lifecycle" do
808 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
810 other_user = insert(:user)
812 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
814 assert Enum.empty?(Notification.for_user(user))
816 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
818 assert length(Notification.for_user(user)) == 1
820 {:ok, _} = CommonAPI.delete(activity.id, user)
822 assert Enum.empty?(Notification.for_user(user))
825 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
827 other_user = insert(:user)
829 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
831 assert Enum.empty?(Notification.for_user(user))
833 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
835 assert length(Notification.for_user(user)) == 1
837 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
839 assert Enum.empty?(Notification.for_user(user))
842 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
844 other_user = insert(:user)
846 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
848 assert Enum.empty?(Notification.for_user(user))
850 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
852 assert length(Notification.for_user(user)) == 1
854 {:ok, _} = CommonAPI.delete(activity.id, user)
856 assert Enum.empty?(Notification.for_user(user))
859 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
861 other_user = insert(:user)
863 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
865 assert Enum.empty?(Notification.for_user(user))
867 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
869 assert length(Notification.for_user(user)) == 1
871 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
873 assert Enum.empty?(Notification.for_user(user))
876 test "liking an activity which is already deleted does not generate a notification" do
878 other_user = insert(:user)
880 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
882 assert Enum.empty?(Notification.for_user(user))
884 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
886 assert Enum.empty?(Notification.for_user(user))
888 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
890 assert Enum.empty?(Notification.for_user(user))
893 test "repeating an activity which is already deleted does not generate a notification" do
895 other_user = insert(:user)
897 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
899 assert Enum.empty?(Notification.for_user(user))
901 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
903 assert Enum.empty?(Notification.for_user(user))
905 {:error, _} = CommonAPI.repeat(activity.id, other_user)
907 assert Enum.empty?(Notification.for_user(user))
910 test "replying to a deleted post without tagging does not generate a notification" do
912 other_user = insert(:user)
914 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
915 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
917 {:ok, _reply_activity} =
918 CommonAPI.post(other_user, %{
919 status: "test reply",
920 in_reply_to_status_id: activity.id
923 assert Enum.empty?(Notification.for_user(user))
926 test "notifications are deleted if a local user is deleted" do
928 other_user = insert(:user)
931 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
933 refute Enum.empty?(Notification.for_user(other_user))
935 {:ok, job} = User.delete(user)
936 ObanHelpers.perform(job)
938 assert Enum.empty?(Notification.for_user(other_user))
941 test "notifications are deleted if a remote user is deleted" do
942 remote_user = insert(:user)
943 local_user = insert(:user)
946 "@context" => "https://www.w3.org/ns/activitystreams",
948 "actor" => remote_user.ap_id,
949 "id" => remote_user.ap_id <> "/activities/test",
950 "to" => [local_user.ap_id],
954 "content" => "Hello!",
958 "href" => local_user.ap_id,
959 "name" => "@#{local_user.nickname}"
962 "to" => [local_user.ap_id],
964 "attributedTo" => remote_user.ap_id
968 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
970 refute Enum.empty?(Notification.for_user(local_user))
972 delete_user_message = %{
973 "@context" => "https://www.w3.org/ns/activitystreams",
974 "id" => remote_user.ap_id <> "/activities/delete",
975 "actor" => remote_user.ap_id,
977 "object" => remote_user.ap_id
980 remote_user_url = remote_user.ap_id
983 %{method: :get, url: ^remote_user_url} ->
984 %Tesla.Env{status: 404, body: ""}
987 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
988 ObanHelpers.perform_all()
990 assert Enum.empty?(Notification.for_user(local_user))
993 test "move activity generates a notification" do
994 %{ap_id: old_ap_id} = old_user = insert(:user)
995 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
996 follower = insert(:user)
997 other_follower = insert(:user, %{allow_following_move: false})
999 User.follow(follower, old_user)
1000 User.follow(other_follower, old_user)
1002 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1003 ObanHelpers.perform_all()
1008 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1011 ] = Notification.for_user(follower)
1016 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1019 ] = Notification.for_user(other_follower)
1023 describe "for_user" do
1025 user = insert(:user)
1027 {:ok, %{user: user}}
1030 test "it returns notifications for muted user without notifications", %{user: user} do
1031 muted = insert(:user)
1032 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1034 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1036 [notification] = Notification.for_user(user)
1038 assert notification.activity.object
1039 assert notification.seen
1042 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1043 muted = insert(:user)
1044 {:ok, _user_relationships} = User.mute(user, muted)
1046 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1048 assert Notification.for_user(user) == []
1051 test "it doesn't return notifications for blocked user", %{user: user} do
1052 blocked = insert(:user)
1053 {:ok, _user_relationship} = User.block(user, blocked)
1055 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1057 assert Notification.for_user(user) == []
1060 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1061 blocked = insert(:user, ap_id: "http://some-domain.com")
1062 {:ok, user} = User.block_domain(user, "some-domain.com")
1064 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1066 assert Notification.for_user(user) == []
1069 test "it returns notifications for domain-blocked but followed user" do
1070 user = insert(:user)
1071 blocked = insert(:user, ap_id: "http://some-domain.com")
1073 {:ok, user} = User.block_domain(user, "some-domain.com")
1074 {:ok, _, _} = User.follow(user, blocked)
1076 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1078 assert length(Notification.for_user(user)) == 1
1081 test "it doesn't return notifications for muted thread", %{user: user} do
1082 another_user = insert(:user)
1084 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1086 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1087 assert Notification.for_user(user) == []
1090 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1091 muted = insert(:user)
1092 {:ok, _user_relationships} = User.mute(user, muted)
1094 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1096 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1099 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1102 blocked = insert(:user)
1103 {:ok, _user_relationship} = User.block(user, blocked)
1105 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1107 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1110 test "when with_muted is set, " <>
1111 "it doesn't return notifications from a domain-blocked non-followed user",
1113 blocked = insert(:user, ap_id: "http://some-domain.com")
1114 {:ok, user} = User.block_domain(user, "some-domain.com")
1116 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1118 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1121 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1122 another_user = insert(:user)
1124 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1126 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1127 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1130 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1131 insert(:filter, user: user, phrase: "cofe", hide: true)
1132 another_user = insert(:user)
1134 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1136 assert Enum.empty?(Notification.for_user(user))
1139 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1140 insert(:filter, user: user, phrase: "test", hide: false)
1141 another_user = insert(:user)
1143 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1145 assert length(Notification.for_user(user)) == 1
1148 test "it returns notifications about favorites with filtered word", %{user: user} do
1149 insert(:filter, user: user, phrase: "cofe", hide: true)
1150 another_user = insert(:user)
1152 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1153 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1155 assert length(Notification.for_user(user)) == 1