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 test "create_poll_notifications/1" do
133 [user1, user2, user3, _, _] = insert_list(5, :user)
134 question = insert(:question, user: user1)
135 activity = insert(:question_activity, question: question)
137 {:ok, _, _} = CommonAPI.vote(user2, question, [0])
138 {:ok, _, _} = CommonAPI.vote(user3, question, [1])
140 {:ok, notifications} = Notification.create_poll_notifications(activity)
142 assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
145 describe "CommonApi.post/2 notification-related functionality" do
146 test_with_mock "creates but does NOT send notification to blocker user",
151 blocker = insert(:user)
152 {:ok, _user_relationship} = User.block(blocker, user)
154 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
156 blocker_id = blocker.id
157 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
158 refute called(Push.send(:_))
161 test_with_mock "creates but does NOT send notification to notification-muter user",
166 muter = insert(:user)
167 {:ok, _user_relationships} = User.mute(muter, user)
169 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
172 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
173 refute called(Push.send(:_))
176 test_with_mock "creates but does NOT send notification to thread-muter user",
181 thread_muter = insert(:user)
183 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
185 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
187 {:ok, _same_context_activity} =
188 CommonAPI.post(user, %{
189 status: "hey-hey-hey @#{thread_muter.nickname}!",
190 in_reply_to_status_id: activity.id
193 [pre_mute_notification, post_mute_notification] =
194 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
196 pre_mute_notification_id = pre_mute_notification.id
197 post_mute_notification_id = post_mute_notification.id
202 %Notification{id: ^pre_mute_notification_id} -> true
211 %Notification{id: ^post_mute_notification_id} -> true
219 describe "create_notification" do
220 @tag needs_streamer: true
221 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
222 %{user: user, token: oauth_token} = oauth_access(["read"])
226 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
227 assert_receive {:render_with_user, _, _, _}, 4_000
230 task_user_notification =
233 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
235 assert_receive {:render_with_user, _, _, _}, 4_000
238 activity = insert(:note_activity)
240 notify = Notification.create_notification(activity, user)
241 assert notify.user_id == user.id
243 Task.await(task_user_notification)
246 test "it creates a notification for user if the user blocks the activity author" do
247 activity = insert(:note_activity)
248 author = User.get_cached_by_ap_id(activity.data["actor"])
250 {:ok, _user_relationship} = User.block(user, author)
252 assert Notification.create_notification(activity, user)
255 test "it creates a notification for the user if the user mutes the activity author" do
256 muter = insert(:user)
257 muted = insert(:user)
258 {:ok, _} = User.mute(muter, muted)
259 muter = Repo.get(User, muter.id)
260 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
262 notification = Notification.create_notification(activity, muter)
264 assert notification.id
265 assert notification.seen
268 test "notification created if user is muted without notifications" do
269 muter = insert(:user)
270 muted = insert(:user)
272 {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
274 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
276 assert Notification.create_notification(activity, muter)
279 test "it creates a notification for an activity from a muted thread" do
280 muter = insert(:user)
281 other_user = insert(:user)
282 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
283 CommonAPI.add_mute(muter, activity)
286 CommonAPI.post(other_user, %{
287 status: "Hi @#{muter.nickname}",
288 in_reply_to_status_id: activity.id
291 notification = Notification.create_notification(activity, muter)
293 assert notification.id
294 assert notification.seen
297 test "it disables notifications from strangers" do
298 follower = insert(:user)
302 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
305 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
306 refute Notification.create_notification(activity, followed)
309 test "it doesn't create a notification for user if he is the activity author" do
310 activity = insert(:note_activity)
311 author = User.get_cached_by_ap_id(activity.data["actor"])
313 refute Notification.create_notification(activity, author)
316 test "it doesn't create duplicate notifications for follow+subscribed users" do
318 subscriber = insert(:user)
320 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
321 User.subscribe(subscriber, user)
322 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
323 {:ok, [_notif]} = Notification.create_notifications(status)
326 test "it doesn't create subscription notifications if the recipient cannot see the status" do
328 subscriber = insert(:user)
330 User.subscribe(subscriber, user)
332 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
334 assert {:ok, []} == Notification.create_notifications(status)
337 test "it disables notifications from people who are invisible" do
338 author = insert(:user, invisible: true)
341 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
342 refute Notification.create_notification(status, user)
345 test "it doesn't create notifications if content matches with an irreversible filter" do
347 subscriber = insert(:user)
349 User.subscribe(subscriber, user)
350 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
352 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
354 assert {:ok, []} == Notification.create_notifications(status)
357 test "it creates notifications if content matches with a not irreversible filter" do
359 subscriber = insert(:user)
361 User.subscribe(subscriber, user)
362 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
364 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
365 {:ok, [notification]} = Notification.create_notifications(status)
368 refute notification.seen
371 test "it creates notifications when someone likes user's status with a filtered word" do
373 other_user = insert(:user)
374 insert(:filter, user: user, phrase: "tesla", hide: true)
376 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
377 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
379 {:ok, [notification]} = Notification.create_notifications(activity_two)
382 refute notification.seen
386 describe "follow / follow_request notifications" do
387 test "it creates `follow` notification for approved Follow activity" do
389 followed_user = insert(:user, is_locked: false)
391 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
392 assert FollowingRelationship.following?(user, followed_user)
393 assert [notification] = Notification.for_user(followed_user)
395 assert %{type: "follow"} =
396 NotificationView.render("show.json", %{
397 notification: notification,
402 test "it creates `follow_request` notification for pending Follow activity" do
404 followed_user = insert(:user, is_locked: true)
406 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
407 refute FollowingRelationship.following?(user, followed_user)
408 assert [notification] = Notification.for_user(followed_user)
410 render_opts = %{notification: notification, for: followed_user}
411 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
413 # After request is accepted, the same notification is rendered with type "follow":
414 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
417 Repo.get(Notification, notification.id)
418 |> Repo.preload(:activity)
420 assert %{type: "follow"} =
421 NotificationView.render("show.json", notification: notification, for: followed_user)
424 test "it doesn't create a notification for follow-unfollow-follow chains" do
426 followed_user = insert(:user, is_locked: false)
428 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
429 assert FollowingRelationship.following?(user, followed_user)
430 assert [notification] = Notification.for_user(followed_user)
432 CommonAPI.unfollow(user, followed_user)
433 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
435 notification_id = notification.id
436 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
439 test "dismisses the notification on follow request rejection" do
440 user = insert(:user, is_locked: true)
441 follower = insert(:user)
442 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
443 assert [_notification] = Notification.for_user(user)
444 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
445 assert [] = Notification.for_user(user)
449 describe "get notification" do
450 test "it gets a notification that belongs to the user" do
452 other_user = insert(:user)
454 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
456 {:ok, [notification]} = Notification.create_notifications(activity)
457 {:ok, notification} = Notification.get(other_user, notification.id)
459 assert notification.user_id == other_user.id
462 test "it returns error if the notification doesn't belong to the user" do
464 other_user = insert(:user)
466 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
468 {:ok, [notification]} = Notification.create_notifications(activity)
469 {:error, _notification} = Notification.get(user, notification.id)
473 describe "dismiss notification" do
474 test "it dismisses a notification that belongs to the user" do
476 other_user = insert(:user)
478 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
480 {:ok, [notification]} = Notification.create_notifications(activity)
481 {:ok, notification} = Notification.dismiss(other_user, notification.id)
483 assert notification.user_id == other_user.id
486 test "it returns error if the notification doesn't belong to the user" do
488 other_user = insert(:user)
490 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
492 {:ok, [notification]} = Notification.create_notifications(activity)
493 {:error, _notification} = Notification.dismiss(user, notification.id)
497 describe "clear notification" do
498 test "it clears all notifications belonging to the user" do
500 other_user = insert(:user)
501 third_user = insert(:user)
504 CommonAPI.post(user, %{
505 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
508 {:ok, _notifs} = Notification.create_notifications(activity)
511 CommonAPI.post(user, %{
512 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
515 {:ok, _notifs} = Notification.create_notifications(activity)
516 Notification.clear(other_user)
518 assert Notification.for_user(other_user) == []
519 assert Notification.for_user(third_user) != []
523 describe "set_read_up_to()" do
524 test "it sets all notifications as read up to a specified notification ID" do
526 other_user = insert(:user)
529 CommonAPI.post(user, %{
530 status: "hey @#{other_user.nickname}!"
534 CommonAPI.post(user, %{
535 status: "hey again @#{other_user.nickname}!"
538 [n2, n1] = Notification.for_user(other_user)
543 CommonAPI.post(user, %{
544 status: "hey yet again @#{other_user.nickname}!"
547 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
549 assert read_notification.activity.object
551 [n3, n2, n1] = Notification.for_user(other_user)
553 assert n1.seen == true
554 assert n2.seen == true
555 assert n3.seen == false
557 assert %Pleroma.Marker{} =
561 user_id: other_user.id,
562 timeline: "notifications"
565 assert m.last_read_id == to_string(n2.id)
569 describe "for_user_since/2" do
570 defp days_ago(days) do
572 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
573 -days * 60 * 60 * 24,
578 test "Returns recent notifications" do
579 user1 = insert(:user)
580 user2 = insert(:user)
582 Enum.each(0..10, fn i ->
584 CommonAPI.post(user1, %{
585 status: "hey ##{i} @#{user2.nickname}!"
589 {old, new} = Enum.split(Notification.for_user(user2), 5)
591 Enum.each(old, fn notification ->
593 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
594 |> Pleroma.Repo.update!()
597 recent_notifications_ids =
599 |> Notification.for_user_since(
600 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
604 Enum.each(old, fn %{id: id} ->
605 refute id in recent_notifications_ids
608 Enum.each(new, fn %{id: id} ->
609 assert id in recent_notifications_ids
614 describe "notification target determination / get_notified_from_activity/2" do
615 test "it sends notifications to addressed users in new messages" do
617 other_user = insert(:user)
620 CommonAPI.post(user, %{
621 status: "hey @#{other_user.nickname}!"
624 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
626 assert other_user in enabled_receivers
629 test "it sends notifications to mentioned users in new messages" do
631 other_user = insert(:user)
634 "@context" => "https://www.w3.org/ns/activitystreams",
636 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
637 "actor" => user.ap_id,
640 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
641 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
642 "content" => "message with a Mention tag, but no explicit tagging",
646 "href" => other_user.ap_id,
647 "name" => other_user.nickname
650 "attributedTo" => user.ap_id
654 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
656 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
658 assert other_user in enabled_receivers
661 test "it does not send notifications to users who are only cc in new messages" do
663 other_user = insert(:user)
666 "@context" => "https://www.w3.org/ns/activitystreams",
668 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
669 "cc" => [other_user.ap_id],
670 "actor" => user.ap_id,
673 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
674 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
675 "cc" => [other_user.ap_id],
676 "content" => "hi everyone",
677 "attributedTo" => user.ap_id
681 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
683 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
685 assert other_user not in enabled_receivers
688 test "it does not send notification to mentioned users 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, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
700 {enabled_receivers, _disabled_receivers} =
701 Notification.get_notified_from_activity(activity_two)
703 assert other_user not in enabled_receivers
706 test "it only notifies the post's author in likes" do
708 other_user = insert(:user)
709 third_user = insert(:user)
711 {:ok, activity_one} =
712 CommonAPI.post(user, %{
713 status: "hey @#{other_user.nickname}!"
716 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
720 |> Map.put("to", [other_user.ap_id | like_data["to"]])
721 |> ActivityPub.persist(local: true)
723 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
725 assert other_user not in enabled_receivers
728 test "it does not send notification to mentioned users in announces" do
730 other_user = insert(:user)
731 third_user = insert(:user)
733 {:ok, activity_one} =
734 CommonAPI.post(user, %{
735 status: "hey @#{other_user.nickname}!"
738 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
740 {enabled_receivers, _disabled_receivers} =
741 Notification.get_notified_from_activity(activity_two)
743 assert other_user not in enabled_receivers
746 test "it returns blocking recipient in disabled recipients list" do
748 other_user = insert(:user)
749 {:ok, _user_relationship} = User.block(other_user, user)
751 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
753 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
755 assert [] == enabled_receivers
756 assert [other_user] == disabled_receivers
759 test "it returns notification-muting recipient in disabled recipients list" do
761 other_user = insert(:user)
762 {:ok, _user_relationships} = User.mute(other_user, user)
764 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
766 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
768 assert [] == enabled_receivers
769 assert [other_user] == disabled_receivers
772 test "it returns thread-muting recipient in disabled recipients list" do
774 other_user = insert(:user)
776 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
778 {:ok, _} = CommonAPI.add_mute(other_user, activity)
780 {:ok, same_context_activity} =
781 CommonAPI.post(user, %{
782 status: "hey-hey-hey @#{other_user.nickname}!",
783 in_reply_to_status_id: activity.id
786 {enabled_receivers, disabled_receivers} =
787 Notification.get_notified_from_activity(same_context_activity)
789 assert [other_user] == disabled_receivers
790 refute other_user in enabled_receivers
793 test "it returns non-following domain-blocking recipient in disabled recipients list" do
794 blocked_domain = "blocked.domain"
795 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
796 other_user = insert(:user)
798 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
800 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
802 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
804 assert [] == enabled_receivers
805 assert [other_user] == disabled_receivers
808 test "it returns following domain-blocking recipient in enabled recipients list" do
809 blocked_domain = "blocked.domain"
810 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
811 other_user = insert(:user)
813 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
814 {:ok, other_user, user} = User.follow(other_user, user)
816 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
818 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
820 assert [other_user] == enabled_receivers
821 assert [] == disabled_receivers
825 describe "notification lifecycle" do
826 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
828 other_user = insert(:user)
830 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
832 assert Enum.empty?(Notification.for_user(user))
834 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
836 assert length(Notification.for_user(user)) == 1
838 {:ok, _} = CommonAPI.delete(activity.id, user)
840 assert Enum.empty?(Notification.for_user(user))
843 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
845 other_user = insert(:user)
847 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
849 assert Enum.empty?(Notification.for_user(user))
851 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
853 assert length(Notification.for_user(user)) == 1
855 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
857 assert Enum.empty?(Notification.for_user(user))
860 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
862 other_user = insert(:user)
864 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
866 assert Enum.empty?(Notification.for_user(user))
868 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
870 assert length(Notification.for_user(user)) == 1
872 {:ok, _} = CommonAPI.delete(activity.id, user)
874 assert Enum.empty?(Notification.for_user(user))
877 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
879 other_user = insert(:user)
881 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
883 assert Enum.empty?(Notification.for_user(user))
885 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
887 assert length(Notification.for_user(user)) == 1
889 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
891 assert Enum.empty?(Notification.for_user(user))
894 test "liking an activity which is already deleted does not generate a notification" do
896 other_user = insert(:user)
898 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
900 assert Enum.empty?(Notification.for_user(user))
902 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
904 assert Enum.empty?(Notification.for_user(user))
906 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
908 assert Enum.empty?(Notification.for_user(user))
911 test "repeating an activity which is already deleted does not generate a notification" do
913 other_user = insert(:user)
915 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
917 assert Enum.empty?(Notification.for_user(user))
919 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
921 assert Enum.empty?(Notification.for_user(user))
923 {:error, _} = CommonAPI.repeat(activity.id, other_user)
925 assert Enum.empty?(Notification.for_user(user))
928 test "replying to a deleted post without tagging does not generate a notification" do
930 other_user = insert(:user)
932 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
933 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
935 {:ok, _reply_activity} =
936 CommonAPI.post(other_user, %{
937 status: "test reply",
938 in_reply_to_status_id: activity.id
941 assert Enum.empty?(Notification.for_user(user))
944 test "notifications are deleted if a local user is deleted" do
946 other_user = insert(:user)
949 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
951 refute Enum.empty?(Notification.for_user(other_user))
953 {:ok, job} = User.delete(user)
954 ObanHelpers.perform(job)
956 assert Enum.empty?(Notification.for_user(other_user))
959 test "notifications are deleted if a remote user is deleted" do
960 remote_user = insert(:user)
961 local_user = insert(:user)
964 "@context" => "https://www.w3.org/ns/activitystreams",
966 "actor" => remote_user.ap_id,
967 "id" => remote_user.ap_id <> "/activities/test",
968 "to" => [local_user.ap_id],
972 "id" => remote_user.ap_id <> "/objects/test",
973 "content" => "Hello!",
977 "href" => local_user.ap_id,
978 "name" => "@#{local_user.nickname}"
981 "to" => [local_user.ap_id],
983 "attributedTo" => remote_user.ap_id
987 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
989 refute Enum.empty?(Notification.for_user(local_user))
991 delete_user_message = %{
992 "@context" => "https://www.w3.org/ns/activitystreams",
993 "id" => remote_user.ap_id <> "/activities/delete",
994 "actor" => remote_user.ap_id,
996 "object" => remote_user.ap_id
999 remote_user_url = remote_user.ap_id
1002 %{method: :get, url: ^remote_user_url} ->
1003 %Tesla.Env{status: 404, body: ""}
1006 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
1007 ObanHelpers.perform_all()
1009 assert Enum.empty?(Notification.for_user(local_user))
1012 test "move activity generates a notification" do
1013 %{ap_id: old_ap_id} = old_user = insert(:user)
1014 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1015 follower = insert(:user)
1016 other_follower = insert(:user, %{allow_following_move: false})
1018 User.follow(follower, old_user)
1019 User.follow(other_follower, old_user)
1021 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1022 ObanHelpers.perform_all()
1027 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1030 ] = Notification.for_user(follower)
1035 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1038 ] = Notification.for_user(other_follower)
1042 describe "for_user" do
1044 user = insert(:user)
1046 {:ok, %{user: user}}
1049 test "it returns notifications for muted user without notifications", %{user: user} do
1050 muted = insert(:user)
1051 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1053 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1055 [notification] = Notification.for_user(user)
1057 assert notification.activity.object
1058 assert notification.seen
1061 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1062 muted = insert(:user)
1063 {:ok, _user_relationships} = User.mute(user, muted)
1065 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1067 assert Notification.for_user(user) == []
1070 test "it doesn't return notifications for blocked user", %{user: user} do
1071 blocked = insert(:user)
1072 {:ok, _user_relationship} = User.block(user, blocked)
1074 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1076 assert Notification.for_user(user) == []
1079 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1080 blocked = insert(:user, ap_id: "http://some-domain.com")
1081 {:ok, user} = User.block_domain(user, "some-domain.com")
1083 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1085 assert Notification.for_user(user) == []
1088 test "it returns notifications for domain-blocked but followed user" do
1089 user = insert(:user)
1090 blocked = insert(:user, ap_id: "http://some-domain.com")
1092 {:ok, user} = User.block_domain(user, "some-domain.com")
1093 {:ok, _, _} = User.follow(user, blocked)
1095 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1097 assert length(Notification.for_user(user)) == 1
1100 test "it doesn't return notifications for muted thread", %{user: user} do
1101 another_user = insert(:user)
1103 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1105 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1106 assert Notification.for_user(user) == []
1109 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1110 muted = insert(:user)
1111 {:ok, _user_relationships} = User.mute(user, muted)
1113 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1115 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1118 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1121 blocked = insert(:user)
1122 {:ok, _user_relationship} = User.block(user, blocked)
1124 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1126 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1129 test "when with_muted is set, " <>
1130 "it doesn't return notifications from a domain-blocked non-followed user",
1132 blocked = insert(:user, ap_id: "http://some-domain.com")
1133 {:ok, user} = User.block_domain(user, "some-domain.com")
1135 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1137 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1140 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1141 another_user = insert(:user)
1143 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1145 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1146 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1149 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1150 insert(:filter, user: user, phrase: "cofe", hide: true)
1151 another_user = insert(:user)
1153 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1155 assert Enum.empty?(Notification.for_user(user))
1158 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1159 insert(:filter, user: user, phrase: "test", hide: false)
1160 another_user = insert(:user)
1162 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1164 assert length(Notification.for_user(user)) == 1
1167 test "it returns notifications about favorites with filtered word", %{user: user} do
1168 insert(:filter, user: user, phrase: "cofe", hide: true)
1169 another_user = insert(:user)
1171 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1172 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1174 assert length(Notification.for_user(user)) == 1