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 [user1.id, user3.id, user2.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 "content" => "message with a Mention tag, but no explicit tagging",
644 "href" => other_user.ap_id,
645 "name" => other_user.nickname
648 "attributedTo" => user.ap_id
652 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
654 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
656 assert other_user in enabled_receivers
659 test "it does not send notifications to users who are only cc in new messages" do
661 other_user = insert(:user)
664 "@context" => "https://www.w3.org/ns/activitystreams",
666 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
667 "cc" => [other_user.ap_id],
668 "actor" => user.ap_id,
671 "content" => "hi everyone",
672 "attributedTo" => user.ap_id
676 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
678 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
680 assert other_user not in enabled_receivers
683 test "it does not send notification to mentioned users in likes" do
685 other_user = insert(:user)
686 third_user = insert(:user)
688 {:ok, activity_one} =
689 CommonAPI.post(user, %{
690 status: "hey @#{other_user.nickname}!"
693 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
695 {enabled_receivers, _disabled_receivers} =
696 Notification.get_notified_from_activity(activity_two)
698 assert other_user not in enabled_receivers
701 test "it only notifies the post's author in likes" do
703 other_user = insert(:user)
704 third_user = insert(:user)
706 {:ok, activity_one} =
707 CommonAPI.post(user, %{
708 status: "hey @#{other_user.nickname}!"
711 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
715 |> Map.put("to", [other_user.ap_id | like_data["to"]])
716 |> ActivityPub.persist(local: true)
718 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
720 assert other_user not in enabled_receivers
723 test "it does not send notification to mentioned users in announces" do
725 other_user = insert(:user)
726 third_user = insert(:user)
728 {:ok, activity_one} =
729 CommonAPI.post(user, %{
730 status: "hey @#{other_user.nickname}!"
733 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
735 {enabled_receivers, _disabled_receivers} =
736 Notification.get_notified_from_activity(activity_two)
738 assert other_user not in enabled_receivers
741 test "it returns blocking recipient in disabled recipients list" do
743 other_user = insert(:user)
744 {:ok, _user_relationship} = User.block(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 notification-muting recipient in disabled recipients list" do
756 other_user = insert(:user)
757 {:ok, _user_relationships} = User.mute(other_user, user)
759 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
761 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
763 assert [] == enabled_receivers
764 assert [other_user] == disabled_receivers
767 test "it returns thread-muting recipient in disabled recipients list" do
769 other_user = insert(:user)
771 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
773 {:ok, _} = CommonAPI.add_mute(other_user, activity)
775 {:ok, same_context_activity} =
776 CommonAPI.post(user, %{
777 status: "hey-hey-hey @#{other_user.nickname}!",
778 in_reply_to_status_id: activity.id
781 {enabled_receivers, disabled_receivers} =
782 Notification.get_notified_from_activity(same_context_activity)
784 assert [other_user] == disabled_receivers
785 refute other_user in enabled_receivers
788 test "it returns non-following domain-blocking recipient in disabled recipients list" do
789 blocked_domain = "blocked.domain"
790 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
791 other_user = insert(:user)
793 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
795 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
797 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
799 assert [] == enabled_receivers
800 assert [other_user] == disabled_receivers
803 test "it returns following domain-blocking recipient in enabled recipients list" do
804 blocked_domain = "blocked.domain"
805 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
806 other_user = insert(:user)
808 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
809 {:ok, other_user, user} = User.follow(other_user, user)
811 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
813 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
815 assert [other_user] == enabled_receivers
816 assert [] == disabled_receivers
820 describe "notification lifecycle" do
821 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
823 other_user = insert(:user)
825 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
827 assert Enum.empty?(Notification.for_user(user))
829 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
831 assert length(Notification.for_user(user)) == 1
833 {:ok, _} = CommonAPI.delete(activity.id, user)
835 assert Enum.empty?(Notification.for_user(user))
838 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
840 other_user = insert(:user)
842 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
844 assert Enum.empty?(Notification.for_user(user))
846 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
848 assert length(Notification.for_user(user)) == 1
850 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
852 assert Enum.empty?(Notification.for_user(user))
855 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
857 other_user = insert(:user)
859 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
861 assert Enum.empty?(Notification.for_user(user))
863 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
865 assert length(Notification.for_user(user)) == 1
867 {:ok, _} = CommonAPI.delete(activity.id, user)
869 assert Enum.empty?(Notification.for_user(user))
872 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
874 other_user = insert(:user)
876 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
878 assert Enum.empty?(Notification.for_user(user))
880 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
882 assert length(Notification.for_user(user)) == 1
884 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
886 assert Enum.empty?(Notification.for_user(user))
889 test "liking an activity which is already deleted does not generate a notification" do
891 other_user = insert(:user)
893 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
895 assert Enum.empty?(Notification.for_user(user))
897 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
899 assert Enum.empty?(Notification.for_user(user))
901 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
903 assert Enum.empty?(Notification.for_user(user))
906 test "repeating an activity which is already deleted does not generate a notification" do
908 other_user = insert(:user)
910 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
912 assert Enum.empty?(Notification.for_user(user))
914 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
916 assert Enum.empty?(Notification.for_user(user))
918 {:error, _} = CommonAPI.repeat(activity.id, other_user)
920 assert Enum.empty?(Notification.for_user(user))
923 test "replying to a deleted post without tagging does not generate a notification" do
925 other_user = insert(:user)
927 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
928 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
930 {:ok, _reply_activity} =
931 CommonAPI.post(other_user, %{
932 status: "test reply",
933 in_reply_to_status_id: activity.id
936 assert Enum.empty?(Notification.for_user(user))
939 test "notifications are deleted if a local user is deleted" do
941 other_user = insert(:user)
944 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
946 refute Enum.empty?(Notification.for_user(other_user))
948 {:ok, job} = User.delete(user)
949 ObanHelpers.perform(job)
951 assert Enum.empty?(Notification.for_user(other_user))
954 test "notifications are deleted if a remote user is deleted" do
955 remote_user = insert(:user)
956 local_user = insert(:user)
959 "@context" => "https://www.w3.org/ns/activitystreams",
961 "actor" => remote_user.ap_id,
962 "id" => remote_user.ap_id <> "/activities/test",
963 "to" => [local_user.ap_id],
967 "content" => "Hello!",
971 "href" => local_user.ap_id,
972 "name" => "@#{local_user.nickname}"
975 "to" => [local_user.ap_id],
977 "attributedTo" => remote_user.ap_id
981 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
983 refute Enum.empty?(Notification.for_user(local_user))
985 delete_user_message = %{
986 "@context" => "https://www.w3.org/ns/activitystreams",
987 "id" => remote_user.ap_id <> "/activities/delete",
988 "actor" => remote_user.ap_id,
990 "object" => remote_user.ap_id
993 remote_user_url = remote_user.ap_id
996 %{method: :get, url: ^remote_user_url} ->
997 %Tesla.Env{status: 404, body: ""}
1000 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
1001 ObanHelpers.perform_all()
1003 assert Enum.empty?(Notification.for_user(local_user))
1006 test "move activity generates a notification" do
1007 %{ap_id: old_ap_id} = old_user = insert(:user)
1008 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1009 follower = insert(:user)
1010 other_follower = insert(:user, %{allow_following_move: false})
1012 User.follow(follower, old_user)
1013 User.follow(other_follower, old_user)
1015 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1016 ObanHelpers.perform_all()
1021 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1024 ] = Notification.for_user(follower)
1029 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1032 ] = Notification.for_user(other_follower)
1036 describe "for_user" do
1038 user = insert(:user)
1040 {:ok, %{user: user}}
1043 test "it returns notifications for muted user without notifications", %{user: user} do
1044 muted = insert(:user)
1045 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1047 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1049 [notification] = Notification.for_user(user)
1051 assert notification.activity.object
1052 assert notification.seen
1055 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1056 muted = insert(:user)
1057 {:ok, _user_relationships} = User.mute(user, muted)
1059 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1061 assert Notification.for_user(user) == []
1064 test "it doesn't return notifications for blocked user", %{user: user} do
1065 blocked = insert(:user)
1066 {:ok, _user_relationship} = User.block(user, blocked)
1068 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1070 assert Notification.for_user(user) == []
1073 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1074 blocked = insert(:user, ap_id: "http://some-domain.com")
1075 {:ok, user} = User.block_domain(user, "some-domain.com")
1077 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1079 assert Notification.for_user(user) == []
1082 test "it returns notifications for domain-blocked but followed user" do
1083 user = insert(:user)
1084 blocked = insert(:user, ap_id: "http://some-domain.com")
1086 {:ok, user} = User.block_domain(user, "some-domain.com")
1087 {:ok, _, _} = User.follow(user, blocked)
1089 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1091 assert length(Notification.for_user(user)) == 1
1094 test "it doesn't return notifications for muted thread", %{user: user} do
1095 another_user = insert(:user)
1097 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1099 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1100 assert Notification.for_user(user) == []
1103 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1104 muted = insert(:user)
1105 {:ok, _user_relationships} = User.mute(user, muted)
1107 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1109 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1112 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1115 blocked = insert(:user)
1116 {:ok, _user_relationship} = User.block(user, blocked)
1118 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1120 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1123 test "when with_muted is set, " <>
1124 "it doesn't return notifications from a domain-blocked non-followed user",
1126 blocked = insert(:user, ap_id: "http://some-domain.com")
1127 {:ok, user} = User.block_domain(user, "some-domain.com")
1129 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1131 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1134 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1135 another_user = insert(:user)
1137 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1139 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1140 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1143 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1144 insert(:filter, user: user, phrase: "cofe", hide: true)
1145 another_user = insert(:user)
1147 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1149 assert Enum.empty?(Notification.for_user(user))
1152 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1153 insert(:filter, user: user, phrase: "test", hide: false)
1154 another_user = insert(:user)
1156 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1158 assert length(Notification.for_user(user)) == 1
1161 test "it returns notifications about favorites with filtered word", %{user: user} do
1162 insert(:filter, user: user, phrase: "cofe", hide: true)
1163 another_user = insert(:user)
1165 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1166 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1168 assert length(Notification.for_user(user)) == 1