1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.NotificationTest do
11 alias Pleroma.Activity
12 alias Pleroma.FollowingRelationship
13 alias Pleroma.Notification
15 alias Pleroma.Tests.ObanHelpers
17 alias Pleroma.Web.ActivityPub.ActivityPub
18 alias Pleroma.Web.ActivityPub.Builder
19 alias Pleroma.Web.ActivityPub.Transmogrifier
20 alias Pleroma.Web.CommonAPI
21 alias Pleroma.Web.MastodonAPI.NotificationView
22 alias Pleroma.Web.Push
23 alias Pleroma.Web.Streamer
25 describe "fill_in_notification_types" do
26 test "it fills in missing notification types" do
28 other_user = insert(:user)
30 {:ok, post} = CommonAPI.post(user, %{status: "yeah, @#{other_user.nickname}"})
31 {:ok, chat} = CommonAPI.post_chat_message(user, other_user, "yo")
32 {:ok, react} = CommonAPI.react_with_emoji(post.id, other_user, "☕")
33 {:ok, like} = CommonAPI.favorite(other_user, post.id)
34 {:ok, react_2} = CommonAPI.react_with_emoji(post.id, other_user, "☕")
38 |> Map.put("type", "EmojiReaction")
42 |> Activity.change(%{data: data})
45 assert {5, nil} = Repo.update_all(Notification, set: [type: nil])
47 Notification.fill_in_notification_types()
49 assert %{type: "mention"} =
50 Repo.get_by(Notification, user_id: other_user.id, activity_id: post.id)
52 assert %{type: "favourite"} =
53 Repo.get_by(Notification, user_id: user.id, activity_id: like.id)
55 assert %{type: "pleroma:emoji_reaction"} =
56 Repo.get_by(Notification, user_id: user.id, activity_id: react.id)
58 assert %{type: "pleroma:emoji_reaction"} =
59 Repo.get_by(Notification, user_id: user.id, activity_id: react_2.id)
61 assert %{type: "pleroma:chat_mention"} =
62 Repo.get_by(Notification, user_id: other_user.id, activity_id: chat.id)
66 describe "create_notifications" do
67 test "creates a notification for an emoji reaction" do
69 other_user = insert(:user)
71 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
72 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
74 {:ok, [notification]} = Notification.create_notifications(activity)
76 assert notification.user_id == user.id
77 assert notification.type == "pleroma:emoji_reaction"
80 test "notifies someone when they are directly addressed" do
82 other_user = insert(:user)
83 third_user = insert(:user)
86 CommonAPI.post(user, %{
87 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
90 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
92 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
93 assert notified_ids == [other_user.id, third_user.id]
94 assert notification.activity_id == activity.id
95 assert notification.type == "mention"
96 assert other_notification.activity_id == activity.id
98 assert [%Pleroma.Marker{unread_count: 2}] =
99 Pleroma.Marker.get_markers(other_user, ["notifications"])
102 test "it creates a notification for subscribed users" do
104 subscriber = insert(:user)
106 User.subscribe(subscriber, user)
108 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
109 {:ok, [notification]} = Notification.create_notifications(status)
111 assert notification.user_id == subscriber.id
114 test "does not create a notification for subscribed users if status is a reply" do
116 other_user = insert(:user)
117 subscriber = insert(:user)
119 User.subscribe(subscriber, other_user)
121 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
123 {:ok, _reply_activity} =
124 CommonAPI.post(other_user, %{
125 status: "test reply",
126 in_reply_to_status_id: activity.id
129 user_notifications = Notification.for_user(user)
130 assert length(user_notifications) == 1
132 subscriber_notifications = Notification.for_user(subscriber)
133 assert Enum.empty?(subscriber_notifications)
137 describe "CommonApi.post/2 notification-related functionality" do
138 test_with_mock "creates but does NOT send notification to blocker user",
143 blocker = insert(:user)
144 {:ok, _user_relationship} = User.block(blocker, user)
146 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
148 blocker_id = blocker.id
149 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
150 refute called(Push.send(:_))
153 test_with_mock "creates but does NOT send notification to notification-muter user",
158 muter = insert(:user)
159 {:ok, _user_relationships} = User.mute(muter, user)
161 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
164 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
165 refute called(Push.send(:_))
168 test_with_mock "creates but does NOT send notification to thread-muter user",
173 thread_muter = insert(:user)
175 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
177 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
179 {:ok, _same_context_activity} =
180 CommonAPI.post(user, %{
181 status: "hey-hey-hey @#{thread_muter.nickname}!",
182 in_reply_to_status_id: activity.id
185 [pre_mute_notification, post_mute_notification] =
186 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
188 pre_mute_notification_id = pre_mute_notification.id
189 post_mute_notification_id = post_mute_notification.id
194 %Notification{id: ^pre_mute_notification_id} -> true
203 %Notification{id: ^post_mute_notification_id} -> true
211 describe "create_notification" do
212 @tag needs_streamer: true
213 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
218 Streamer.get_topic_and_add_socket("user", user)
219 assert_receive {:render_with_user, _, _, _}, 4_000
222 task_user_notification =
224 Streamer.get_topic_and_add_socket("user:notification", user)
225 assert_receive {:render_with_user, _, _, _}, 4_000
228 activity = insert(:note_activity)
230 notify = Notification.create_notification(activity, user)
231 assert notify.user_id == user.id
233 Task.await(task_user_notification)
236 test "it creates a notification for user if the user blocks the activity author" do
237 activity = insert(:note_activity)
238 author = User.get_cached_by_ap_id(activity.data["actor"])
240 {:ok, _user_relationship} = User.block(user, author)
242 assert Notification.create_notification(activity, user)
245 test "it creates a notification for the user if the user mutes the activity author" do
246 muter = insert(:user)
247 muted = insert(:user)
248 {:ok, _} = User.mute(muter, muted)
249 muter = Repo.get(User, muter.id)
250 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
252 assert Notification.create_notification(activity, muter)
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, 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 assert Notification.create_notification(activity, muter)
281 test "it disables notifications from followers" do
282 follower = insert(:user)
285 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
287 User.follow(follower, followed)
288 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
289 refute Notification.create_notification(activity, followed)
292 test "it disables notifications from non-followers" do
293 follower = insert(:user)
297 notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
300 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
301 refute Notification.create_notification(activity, followed)
304 test "it disables notifications from people the user follows" do
306 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{follows: false})
308 followed = insert(:user)
309 User.follow(follower, followed)
310 follower = Repo.get(User, follower.id)
311 {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
312 refute Notification.create_notification(activity, follower)
315 test "it disables notifications from people the user does not follow" do
317 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
319 followed = insert(:user)
320 {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
321 refute Notification.create_notification(activity, follower)
324 test "it doesn't create a notification for user if he is the activity author" do
325 activity = insert(:note_activity)
326 author = User.get_cached_by_ap_id(activity.data["actor"])
328 refute Notification.create_notification(activity, author)
331 test "it doesn't create duplicate notifications for follow+subscribed users" do
333 subscriber = insert(:user)
335 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
336 User.subscribe(subscriber, user)
337 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
338 {:ok, [_notif]} = Notification.create_notifications(status)
341 test "it doesn't create subscription notifications if the recipient cannot see the status" do
343 subscriber = insert(:user)
345 User.subscribe(subscriber, user)
347 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
349 assert {:ok, []} == Notification.create_notifications(status)
353 describe "follow / follow_request notifications" do
354 test "it creates `follow` notification for approved Follow activity" do
356 followed_user = insert(:user, locked: false)
358 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
359 assert FollowingRelationship.following?(user, followed_user)
360 assert [notification] = Notification.for_user(followed_user)
362 assert %{type: "follow"} =
363 NotificationView.render("show.json", %{
364 notification: notification,
369 test "it creates `follow_request` notification for pending Follow activity" do
371 followed_user = insert(:user, locked: true)
373 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
374 refute FollowingRelationship.following?(user, followed_user)
375 assert [notification] = Notification.for_user(followed_user)
377 render_opts = %{notification: notification, for: followed_user}
378 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
380 # After request is accepted, the same notification is rendered with type "follow":
381 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
384 Repo.get(Notification, notification.id)
385 |> Repo.preload(:activity)
387 assert %{type: "follow"} =
388 NotificationView.render("show.json", notification: notification, for: followed_user)
391 test "it doesn't create a notification for follow-unfollow-follow chains" do
393 followed_user = insert(:user, locked: false)
395 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
396 assert FollowingRelationship.following?(user, followed_user)
397 assert [notification] = Notification.for_user(followed_user)
399 CommonAPI.unfollow(user, followed_user)
400 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
402 notification_id = notification.id
403 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
406 test "dismisses the notification on follow request rejection" do
407 user = insert(:user, locked: true)
408 follower = insert(:user)
409 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
410 assert [notification] = Notification.for_user(user)
411 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
412 assert [] = Notification.for_user(user)
416 describe "get notification" do
417 test "it gets a notification that belongs to the user" do
419 other_user = insert(:user)
421 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
423 {:ok, [notification]} = Notification.create_notifications(activity)
424 {:ok, notification} = Notification.get(other_user, notification.id)
426 assert notification.user_id == other_user.id
429 test "it returns error if the notification doesn't belong to the user" do
431 other_user = insert(:user)
433 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
435 {:ok, [notification]} = Notification.create_notifications(activity)
436 {:error, _notification} = Notification.get(user, notification.id)
440 describe "dismiss notification" do
441 test "it dismisses a notification that belongs to the user" do
443 other_user = insert(:user)
445 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
447 {:ok, [notification]} = Notification.create_notifications(activity)
448 {:ok, notification} = Notification.dismiss(other_user, notification.id)
450 assert notification.user_id == other_user.id
453 test "it returns error if the notification doesn't belong to the user" do
455 other_user = insert(:user)
457 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
459 {:ok, [notification]} = Notification.create_notifications(activity)
460 {:error, _notification} = Notification.dismiss(user, notification.id)
464 describe "clear notification" do
465 test "it clears all notifications belonging to the user" do
467 other_user = insert(:user)
468 third_user = insert(:user)
471 CommonAPI.post(user, %{
472 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
475 {:ok, _notifs} = Notification.create_notifications(activity)
478 CommonAPI.post(user, %{
479 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
482 {:ok, _notifs} = Notification.create_notifications(activity)
483 Notification.clear(other_user)
485 assert Notification.for_user(other_user) == []
486 assert Notification.for_user(third_user) != []
490 describe "set_read_up_to()" do
491 test "it sets all notifications as read up to a specified notification ID" do
493 other_user = insert(:user)
496 CommonAPI.post(user, %{
497 status: "hey @#{other_user.nickname}!"
501 CommonAPI.post(user, %{
502 status: "hey again @#{other_user.nickname}!"
505 [n2, n1] = Notification.for_user(other_user)
510 CommonAPI.post(user, %{
511 status: "hey yet again @#{other_user.nickname}!"
514 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
516 assert read_notification.activity.object
518 [n3, n2, n1] = Notification.for_user(other_user)
520 assert n1.seen == true
521 assert n2.seen == true
522 assert n3.seen == false
524 assert %Pleroma.Marker{} =
528 user_id: other_user.id,
529 timeline: "notifications"
532 assert m.last_read_id == to_string(n2.id)
536 describe "for_user_since/2" do
537 defp days_ago(days) do
539 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
540 -days * 60 * 60 * 24,
545 test "Returns recent notifications" do
546 user1 = insert(:user)
547 user2 = insert(:user)
549 Enum.each(0..10, fn i ->
551 CommonAPI.post(user1, %{
552 status: "hey ##{i} @#{user2.nickname}!"
556 {old, new} = Enum.split(Notification.for_user(user2), 5)
558 Enum.each(old, fn notification ->
560 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
561 |> Pleroma.Repo.update!()
564 recent_notifications_ids =
566 |> Notification.for_user_since(
567 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
571 Enum.each(old, fn %{id: id} ->
572 refute id in recent_notifications_ids
575 Enum.each(new, fn %{id: id} ->
576 assert id in recent_notifications_ids
581 describe "notification target determination / get_notified_from_activity/2" do
582 test "it sends notifications to addressed users in new messages" do
584 other_user = insert(:user)
587 CommonAPI.post(user, %{
588 status: "hey @#{other_user.nickname}!"
591 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
593 assert other_user in enabled_receivers
596 test "it sends notifications to mentioned users in new messages" do
598 other_user = insert(:user)
601 "@context" => "https://www.w3.org/ns/activitystreams",
603 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
604 "actor" => user.ap_id,
607 "content" => "message with a Mention tag, but no explicit tagging",
611 "href" => other_user.ap_id,
612 "name" => other_user.nickname
615 "attributedTo" => user.ap_id
619 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
621 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
623 assert other_user in enabled_receivers
626 test "it does not send notifications to users who are only cc in new messages" do
628 other_user = insert(:user)
631 "@context" => "https://www.w3.org/ns/activitystreams",
633 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
634 "cc" => [other_user.ap_id],
635 "actor" => user.ap_id,
638 "content" => "hi everyone",
639 "attributedTo" => user.ap_id
643 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
645 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
647 assert other_user not in enabled_receivers
650 test "it does not send notification to mentioned users in likes" do
652 other_user = insert(:user)
653 third_user = insert(:user)
655 {:ok, activity_one} =
656 CommonAPI.post(user, %{
657 status: "hey @#{other_user.nickname}!"
660 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
662 {enabled_receivers, _disabled_receivers} =
663 Notification.get_notified_from_activity(activity_two)
665 assert other_user not in enabled_receivers
668 test "it only notifies the post's author in likes" do
670 other_user = insert(:user)
671 third_user = insert(:user)
673 {:ok, activity_one} =
674 CommonAPI.post(user, %{
675 status: "hey @#{other_user.nickname}!"
678 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
682 |> Map.put("to", [other_user.ap_id | like_data["to"]])
683 |> ActivityPub.persist(local: true)
685 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
687 assert other_user not in enabled_receivers
690 test "it does not send notification to mentioned users in announces" do
692 other_user = insert(:user)
693 third_user = insert(:user)
695 {:ok, activity_one} =
696 CommonAPI.post(user, %{
697 status: "hey @#{other_user.nickname}!"
700 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
702 {enabled_receivers, _disabled_receivers} =
703 Notification.get_notified_from_activity(activity_two)
705 assert other_user not in enabled_receivers
708 test "it returns blocking recipient in disabled recipients list" do
710 other_user = insert(:user)
711 {:ok, _user_relationship} = User.block(other_user, user)
713 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
715 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
717 assert [] == enabled_receivers
718 assert [other_user] == disabled_receivers
721 test "it returns notification-muting recipient in disabled recipients list" do
723 other_user = insert(:user)
724 {:ok, _user_relationships} = User.mute(other_user, user)
726 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
728 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
730 assert [] == enabled_receivers
731 assert [other_user] == disabled_receivers
734 test "it returns thread-muting recipient in disabled recipients list" do
736 other_user = insert(:user)
738 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
740 {:ok, _} = CommonAPI.add_mute(other_user, activity)
742 {:ok, same_context_activity} =
743 CommonAPI.post(user, %{
744 status: "hey-hey-hey @#{other_user.nickname}!",
745 in_reply_to_status_id: activity.id
748 {enabled_receivers, disabled_receivers} =
749 Notification.get_notified_from_activity(same_context_activity)
751 assert [other_user] == disabled_receivers
752 refute other_user in enabled_receivers
755 test "it returns non-following domain-blocking recipient in disabled recipients list" do
756 blocked_domain = "blocked.domain"
757 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
758 other_user = insert(:user)
760 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
762 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
764 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
766 assert [] == enabled_receivers
767 assert [other_user] == disabled_receivers
770 test "it returns following domain-blocking recipient in enabled recipients list" do
771 blocked_domain = "blocked.domain"
772 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
773 other_user = insert(:user)
775 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
776 {:ok, other_user} = User.follow(other_user, user)
778 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
780 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
782 assert [other_user] == enabled_receivers
783 assert [] == disabled_receivers
787 describe "notification lifecycle" do
788 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
790 other_user = insert(:user)
792 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
794 assert Enum.empty?(Notification.for_user(user))
796 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
798 assert length(Notification.for_user(user)) == 1
800 {:ok, _} = CommonAPI.delete(activity.id, user)
802 assert Enum.empty?(Notification.for_user(user))
805 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
807 other_user = insert(:user)
809 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
811 assert Enum.empty?(Notification.for_user(user))
813 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
815 assert length(Notification.for_user(user)) == 1
817 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
819 assert Enum.empty?(Notification.for_user(user))
822 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
824 other_user = insert(:user)
826 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
828 assert Enum.empty?(Notification.for_user(user))
830 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
832 assert length(Notification.for_user(user)) == 1
834 {:ok, _} = CommonAPI.delete(activity.id, user)
836 assert Enum.empty?(Notification.for_user(user))
839 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
841 other_user = insert(:user)
843 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
845 assert Enum.empty?(Notification.for_user(user))
847 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
849 assert length(Notification.for_user(user)) == 1
851 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
853 assert Enum.empty?(Notification.for_user(user))
856 test "liking an activity which is already deleted does not generate a notification" do
858 other_user = insert(:user)
860 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
862 assert Enum.empty?(Notification.for_user(user))
864 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
866 assert Enum.empty?(Notification.for_user(user))
868 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
870 assert Enum.empty?(Notification.for_user(user))
873 test "repeating an activity which is already deleted does not generate a notification" do
875 other_user = insert(:user)
877 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
879 assert Enum.empty?(Notification.for_user(user))
881 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
883 assert Enum.empty?(Notification.for_user(user))
885 {:error, _} = CommonAPI.repeat(activity.id, other_user)
887 assert Enum.empty?(Notification.for_user(user))
890 test "replying to a deleted post without tagging does not generate a notification" do
892 other_user = insert(:user)
894 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
895 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
897 {:ok, _reply_activity} =
898 CommonAPI.post(other_user, %{
899 status: "test reply",
900 in_reply_to_status_id: activity.id
903 assert Enum.empty?(Notification.for_user(user))
906 test "notifications are deleted if a local user is deleted" do
908 other_user = insert(:user)
911 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
913 refute Enum.empty?(Notification.for_user(other_user))
915 {:ok, job} = User.delete(user)
916 ObanHelpers.perform(job)
918 assert Enum.empty?(Notification.for_user(other_user))
921 test "notifications are deleted if a remote user is deleted" do
922 remote_user = insert(:user)
923 local_user = insert(:user)
926 "@context" => "https://www.w3.org/ns/activitystreams",
928 "actor" => remote_user.ap_id,
929 "id" => remote_user.ap_id <> "/activities/test",
930 "to" => [local_user.ap_id],
934 "content" => "Hello!",
938 "href" => local_user.ap_id,
939 "name" => "@#{local_user.nickname}"
942 "to" => [local_user.ap_id],
944 "attributedTo" => remote_user.ap_id
948 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
950 refute Enum.empty?(Notification.for_user(local_user))
952 delete_user_message = %{
953 "@context" => "https://www.w3.org/ns/activitystreams",
954 "id" => remote_user.ap_id <> "/activities/delete",
955 "actor" => remote_user.ap_id,
957 "object" => remote_user.ap_id
960 remote_user_url = remote_user.ap_id
963 %{method: :get, url: ^remote_user_url} ->
964 %Tesla.Env{status: 404, body: ""}
967 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
968 ObanHelpers.perform_all()
970 assert Enum.empty?(Notification.for_user(local_user))
973 @tag capture_log: true
974 test "move activity generates a notification" do
975 %{ap_id: old_ap_id} = old_user = insert(:user)
976 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
977 follower = insert(:user)
978 other_follower = insert(:user, %{allow_following_move: false})
980 User.follow(follower, old_user)
981 User.follow(other_follower, old_user)
983 old_user_url = old_user.ap_id
986 File.read!("test/fixtures/users_mock/localhost.json")
987 |> String.replace("{{nickname}}", old_user.nickname)
991 %{method: :get, url: ^old_user_url} ->
992 %Tesla.Env{status: 200, body: body}
995 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
996 ObanHelpers.perform_all()
1001 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1004 ] = Notification.for_user(follower)
1009 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1012 ] = Notification.for_user(other_follower)
1016 describe "for_user" do
1017 test "it returns notifications for muted user without notifications" do
1018 user = insert(:user)
1019 muted = insert(:user)
1020 {:ok, _user_relationships} = User.mute(user, muted, false)
1022 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1024 [notification] = Notification.for_user(user)
1026 assert notification.activity.object
1029 test "it doesn't return notifications for muted user with notifications" do
1030 user = insert(:user)
1031 muted = insert(:user)
1032 {:ok, _user_relationships} = User.mute(user, muted)
1034 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1036 assert Notification.for_user(user) == []
1039 test "it doesn't return notifications for blocked user" do
1040 user = insert(:user)
1041 blocked = insert(:user)
1042 {:ok, _user_relationship} = User.block(user, blocked)
1044 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1046 assert Notification.for_user(user) == []
1049 test "it doesn't return notifications for domain-blocked non-followed user" do
1050 user = insert(:user)
1051 blocked = insert(:user, ap_id: "http://some-domain.com")
1052 {:ok, user} = User.block_domain(user, "some-domain.com")
1054 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1056 assert Notification.for_user(user) == []
1059 test "it returns notifications for domain-blocked but followed user" do
1060 user = insert(:user)
1061 blocked = insert(:user, ap_id: "http://some-domain.com")
1063 {:ok, user} = User.block_domain(user, "some-domain.com")
1064 {:ok, _} = User.follow(user, blocked)
1066 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1068 assert length(Notification.for_user(user)) == 1
1071 test "it doesn't return notifications for muted thread" do
1072 user = insert(:user)
1073 another_user = insert(:user)
1075 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1077 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1078 assert Notification.for_user(user) == []
1081 test "it returns notifications from a muted user when with_muted is set" do
1082 user = insert(:user)
1083 muted = insert(:user)
1084 {:ok, _user_relationships} = User.mute(user, muted)
1086 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1088 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1091 test "it doesn't return notifications from a blocked user when with_muted is set" do
1092 user = insert(:user)
1093 blocked = insert(:user)
1094 {:ok, _user_relationship} = User.block(user, blocked)
1096 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1098 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1101 test "when with_muted is set, " <>
1102 "it doesn't return notifications from a domain-blocked non-followed user" do
1103 user = insert(:user)
1104 blocked = insert(:user, ap_id: "http://some-domain.com")
1105 {:ok, user} = User.block_domain(user, "some-domain.com")
1107 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1109 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1112 test "it returns notifications from muted threads when with_muted is set" do
1113 user = insert(:user)
1114 another_user = insert(:user)
1116 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1118 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1119 assert length(Notification.for_user(user, %{with_muted: true})) == 1