1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.NotificationTest do
11 alias Pleroma.FollowingRelationship
12 alias Pleroma.Notification
13 alias Pleroma.Tests.ObanHelpers
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.ActivityPub.Builder
17 alias Pleroma.Web.ActivityPub.Transmogrifier
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.MastodonAPI.NotificationView
20 alias Pleroma.Web.Push
21 alias Pleroma.Web.Streamer
23 describe "fill_in_notification_types" do
24 test "it fills in missing notification types" do
26 other_user = insert(:user)
28 {:ok, post} = CommonAPI.post(user, %{status: "yeah, @#{other_user.nickname}"})
29 {:ok, chat} = CommonAPI.post_chat_message(user, other_user, "yo")
30 {:ok, react} = CommonAPI.react_with_emoji(post.id, other_user, "☕")
31 {:ok, like} = CommonAPI.favorite(other_user, post.id)
33 assert {4, nil} = Repo.update_all(Notification, set: [type: nil])
35 Notification.fill_in_notification_types()
37 assert %{type: "mention"} =
38 Repo.get_by(Notification, user_id: other_user.id, activity_id: post.id)
40 assert %{type: "favourite"} =
41 Repo.get_by(Notification, user_id: user.id, activity_id: like.id)
43 assert %{type: "pleroma:emoji_reaction"} =
44 Repo.get_by(Notification, user_id: user.id, activity_id: react.id)
46 assert %{type: "pleroma:chat_mention"} =
47 Repo.get_by(Notification, user_id: other_user.id, activity_id: chat.id)
51 describe "create_notifications" do
52 test "creates a notification for an emoji reaction" do
54 other_user = insert(:user)
56 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
57 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
59 {:ok, [notification]} = Notification.create_notifications(activity)
61 assert notification.user_id == user.id
62 assert notification.type == "pleroma:emoji_reaction"
65 test "notifies someone when they are directly addressed" do
67 other_user = insert(:user)
68 third_user = insert(:user)
71 CommonAPI.post(user, %{
72 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
75 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
77 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
78 assert notified_ids == [other_user.id, third_user.id]
79 assert notification.activity_id == activity.id
80 assert notification.type == "mention"
81 assert other_notification.activity_id == activity.id
83 assert [%Pleroma.Marker{unread_count: 2}] =
84 Pleroma.Marker.get_markers(other_user, ["notifications"])
87 test "it creates a notification for subscribed users" do
89 subscriber = insert(:user)
91 User.subscribe(subscriber, user)
93 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
94 {:ok, [notification]} = Notification.create_notifications(status)
96 assert notification.user_id == subscriber.id
99 test "does not create a notification for subscribed users if status is a reply" do
101 other_user = insert(:user)
102 subscriber = insert(:user)
104 User.subscribe(subscriber, other_user)
106 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
108 {:ok, _reply_activity} =
109 CommonAPI.post(other_user, %{
110 status: "test reply",
111 in_reply_to_status_id: activity.id
114 user_notifications = Notification.for_user(user)
115 assert length(user_notifications) == 1
117 subscriber_notifications = Notification.for_user(subscriber)
118 assert Enum.empty?(subscriber_notifications)
122 describe "CommonApi.post/2 notification-related functionality" do
123 test_with_mock "creates but does NOT send notification to blocker user",
128 blocker = insert(:user)
129 {:ok, _user_relationship} = User.block(blocker, user)
131 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
133 blocker_id = blocker.id
134 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
135 refute called(Push.send(:_))
138 test_with_mock "creates but does NOT send notification to notification-muter user",
143 muter = insert(:user)
144 {:ok, _user_relationships} = User.mute(muter, user)
146 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
149 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
150 refute called(Push.send(:_))
153 test_with_mock "creates but does NOT send notification to thread-muter user",
158 thread_muter = insert(:user)
160 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
162 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
164 {:ok, _same_context_activity} =
165 CommonAPI.post(user, %{
166 status: "hey-hey-hey @#{thread_muter.nickname}!",
167 in_reply_to_status_id: activity.id
170 [pre_mute_notification, post_mute_notification] =
171 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
173 pre_mute_notification_id = pre_mute_notification.id
174 post_mute_notification_id = post_mute_notification.id
179 %Notification{id: ^pre_mute_notification_id} -> true
188 %Notification{id: ^post_mute_notification_id} -> true
196 describe "create_notification" do
197 @tag needs_streamer: true
198 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
203 Streamer.get_topic_and_add_socket("user", user)
204 assert_receive {:render_with_user, _, _, _}, 4_000
207 task_user_notification =
209 Streamer.get_topic_and_add_socket("user:notification", user)
210 assert_receive {:render_with_user, _, _, _}, 4_000
213 activity = insert(:note_activity)
215 notify = Notification.create_notification(activity, user)
216 assert notify.user_id == user.id
218 Task.await(task_user_notification)
221 test "it creates a notification for user if the user blocks the activity author" do
222 activity = insert(:note_activity)
223 author = User.get_cached_by_ap_id(activity.data["actor"])
225 {:ok, _user_relationship} = User.block(user, author)
227 assert Notification.create_notification(activity, user)
230 test "it creates a notification for the user if the user mutes the activity author" do
231 muter = insert(:user)
232 muted = insert(:user)
233 {:ok, _} = User.mute(muter, muted)
234 muter = Repo.get(User, muter.id)
235 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
237 assert Notification.create_notification(activity, muter)
240 test "notification created if user is muted without notifications" do
241 muter = insert(:user)
242 muted = insert(:user)
244 {:ok, _user_relationships} = User.mute(muter, muted, false)
246 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
248 assert Notification.create_notification(activity, muter)
251 test "it creates a notification for an activity from a muted thread" do
252 muter = insert(:user)
253 other_user = insert(:user)
254 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
255 CommonAPI.add_mute(muter, activity)
258 CommonAPI.post(other_user, %{
259 status: "Hi @#{muter.nickname}",
260 in_reply_to_status_id: activity.id
263 assert Notification.create_notification(activity, muter)
266 test "it disables notifications from followers" do
267 follower = insert(:user)
270 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
272 User.follow(follower, followed)
273 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
274 refute Notification.create_notification(activity, followed)
277 test "it disables notifications from non-followers" do
278 follower = insert(:user)
282 notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
285 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
286 refute Notification.create_notification(activity, followed)
289 test "it disables notifications from people the user follows" do
291 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{follows: false})
293 followed = insert(:user)
294 User.follow(follower, followed)
295 follower = Repo.get(User, follower.id)
296 {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
297 refute Notification.create_notification(activity, follower)
300 test "it disables notifications from people the user does not follow" do
302 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
304 followed = insert(:user)
305 {:ok, activity} = CommonAPI.post(followed, %{status: "hey @#{follower.nickname}"})
306 refute Notification.create_notification(activity, follower)
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)
338 describe "follow / follow_request notifications" do
339 test "it creates `follow` notification for approved Follow activity" do
341 followed_user = insert(:user, locked: false)
343 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
344 assert FollowingRelationship.following?(user, followed_user)
345 assert [notification] = Notification.for_user(followed_user)
347 assert %{type: "follow"} =
348 NotificationView.render("show.json", %{
349 notification: notification,
354 test "it creates `follow_request` notification for pending Follow activity" do
356 followed_user = insert(:user, locked: true)
358 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
359 refute FollowingRelationship.following?(user, followed_user)
360 assert [notification] = Notification.for_user(followed_user)
362 render_opts = %{notification: notification, for: followed_user}
363 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
365 # After request is accepted, the same notification is rendered with type "follow":
366 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
369 Repo.get(Notification, notification.id)
370 |> Repo.preload(:activity)
372 assert %{type: "follow"} =
373 NotificationView.render("show.json", notification: notification, for: followed_user)
376 test "it doesn't create a notification for follow-unfollow-follow chains" do
378 followed_user = insert(:user, locked: false)
380 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
381 assert FollowingRelationship.following?(user, followed_user)
382 assert [notification] = Notification.for_user(followed_user)
384 CommonAPI.unfollow(user, followed_user)
385 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
387 notification_id = notification.id
388 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
391 test "dismisses the notification on follow request rejection" do
392 user = insert(:user, locked: true)
393 follower = insert(:user)
394 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
395 assert [notification] = Notification.for_user(user)
396 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
397 assert [] = Notification.for_user(user)
401 describe "get notification" do
402 test "it gets a notification that belongs to the user" do
404 other_user = insert(:user)
406 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
408 {:ok, [notification]} = Notification.create_notifications(activity)
409 {:ok, notification} = Notification.get(other_user, notification.id)
411 assert notification.user_id == other_user.id
414 test "it returns error if the notification doesn't belong to the user" do
416 other_user = insert(:user)
418 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
420 {:ok, [notification]} = Notification.create_notifications(activity)
421 {:error, _notification} = Notification.get(user, notification.id)
425 describe "dismiss notification" do
426 test "it dismisses a notification that belongs to the user" do
428 other_user = insert(:user)
430 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
432 {:ok, [notification]} = Notification.create_notifications(activity)
433 {:ok, notification} = Notification.dismiss(other_user, notification.id)
435 assert notification.user_id == other_user.id
438 test "it returns error if the notification doesn't belong to the user" do
440 other_user = insert(:user)
442 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
444 {:ok, [notification]} = Notification.create_notifications(activity)
445 {:error, _notification} = Notification.dismiss(user, notification.id)
449 describe "clear notification" do
450 test "it clears all notifications belonging to the user" do
452 other_user = insert(:user)
453 third_user = insert(:user)
456 CommonAPI.post(user, %{
457 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
460 {:ok, _notifs} = Notification.create_notifications(activity)
463 CommonAPI.post(user, %{
464 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
467 {:ok, _notifs} = Notification.create_notifications(activity)
468 Notification.clear(other_user)
470 assert Notification.for_user(other_user) == []
471 assert Notification.for_user(third_user) != []
475 describe "set_read_up_to()" do
476 test "it sets all notifications as read up to a specified notification ID" do
478 other_user = insert(:user)
481 CommonAPI.post(user, %{
482 status: "hey @#{other_user.nickname}!"
486 CommonAPI.post(user, %{
487 status: "hey again @#{other_user.nickname}!"
490 [n2, n1] = Notification.for_user(other_user)
495 CommonAPI.post(user, %{
496 status: "hey yet again @#{other_user.nickname}!"
499 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
501 assert read_notification.activity.object
503 [n3, n2, n1] = Notification.for_user(other_user)
505 assert n1.seen == true
506 assert n2.seen == true
507 assert n3.seen == false
509 assert %Pleroma.Marker{} =
513 user_id: other_user.id,
514 timeline: "notifications"
517 assert m.last_read_id == to_string(n2.id)
521 describe "for_user_since/2" do
522 defp days_ago(days) do
524 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
525 -days * 60 * 60 * 24,
530 test "Returns recent notifications" do
531 user1 = insert(:user)
532 user2 = insert(:user)
534 Enum.each(0..10, fn i ->
536 CommonAPI.post(user1, %{
537 status: "hey ##{i} @#{user2.nickname}!"
541 {old, new} = Enum.split(Notification.for_user(user2), 5)
543 Enum.each(old, fn notification ->
545 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
546 |> Pleroma.Repo.update!()
549 recent_notifications_ids =
551 |> Notification.for_user_since(
552 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
556 Enum.each(old, fn %{id: id} ->
557 refute id in recent_notifications_ids
560 Enum.each(new, fn %{id: id} ->
561 assert id in recent_notifications_ids
566 describe "notification target determination / get_notified_from_activity/2" do
567 test "it sends notifications to addressed users in new messages" do
569 other_user = insert(:user)
572 CommonAPI.post(user, %{
573 status: "hey @#{other_user.nickname}!"
576 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
578 assert other_user in enabled_receivers
581 test "it sends notifications to mentioned users in new messages" do
583 other_user = insert(:user)
586 "@context" => "https://www.w3.org/ns/activitystreams",
588 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
589 "actor" => user.ap_id,
592 "content" => "message with a Mention tag, but no explicit tagging",
596 "href" => other_user.ap_id,
597 "name" => other_user.nickname
600 "attributedTo" => user.ap_id
604 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
606 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
608 assert other_user in enabled_receivers
611 test "it does not send notifications to users who are only cc in new messages" do
613 other_user = insert(:user)
616 "@context" => "https://www.w3.org/ns/activitystreams",
618 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
619 "cc" => [other_user.ap_id],
620 "actor" => user.ap_id,
623 "content" => "hi everyone",
624 "attributedTo" => user.ap_id
628 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
630 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
632 assert other_user not in enabled_receivers
635 test "it does not send notification to mentioned users in likes" do
637 other_user = insert(:user)
638 third_user = insert(:user)
640 {:ok, activity_one} =
641 CommonAPI.post(user, %{
642 status: "hey @#{other_user.nickname}!"
645 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
647 {enabled_receivers, _disabled_receivers} =
648 Notification.get_notified_from_activity(activity_two)
650 assert other_user not in enabled_receivers
653 test "it only notifies the post's author in likes" do
655 other_user = insert(:user)
656 third_user = insert(:user)
658 {:ok, activity_one} =
659 CommonAPI.post(user, %{
660 status: "hey @#{other_user.nickname}!"
663 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
667 |> Map.put("to", [other_user.ap_id | like_data["to"]])
668 |> ActivityPub.persist(local: true)
670 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
672 assert other_user not in enabled_receivers
675 test "it does not send notification to mentioned users in announces" do
677 other_user = insert(:user)
678 third_user = insert(:user)
680 {:ok, activity_one} =
681 CommonAPI.post(user, %{
682 status: "hey @#{other_user.nickname}!"
685 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
687 {enabled_receivers, _disabled_receivers} =
688 Notification.get_notified_from_activity(activity_two)
690 assert other_user not in enabled_receivers
693 test "it returns blocking recipient in disabled recipients list" do
695 other_user = insert(:user)
696 {:ok, _user_relationship} = User.block(other_user, user)
698 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
700 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
702 assert [] == enabled_receivers
703 assert [other_user] == disabled_receivers
706 test "it returns notification-muting recipient in disabled recipients list" do
708 other_user = insert(:user)
709 {:ok, _user_relationships} = User.mute(other_user, user)
711 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
713 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
715 assert [] == enabled_receivers
716 assert [other_user] == disabled_receivers
719 test "it returns thread-muting recipient in disabled recipients list" do
721 other_user = insert(:user)
723 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
725 {:ok, _} = CommonAPI.add_mute(other_user, activity)
727 {:ok, same_context_activity} =
728 CommonAPI.post(user, %{
729 status: "hey-hey-hey @#{other_user.nickname}!",
730 in_reply_to_status_id: activity.id
733 {enabled_receivers, disabled_receivers} =
734 Notification.get_notified_from_activity(same_context_activity)
736 assert [other_user] == disabled_receivers
737 refute other_user in enabled_receivers
740 test "it returns non-following domain-blocking recipient in disabled recipients list" do
741 blocked_domain = "blocked.domain"
742 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
743 other_user = insert(:user)
745 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
747 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
749 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
751 assert [] == enabled_receivers
752 assert [other_user] == disabled_receivers
755 test "it returns following domain-blocking recipient in enabled 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)
761 {:ok, other_user} = User.follow(other_user, user)
763 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
765 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
767 assert [other_user] == enabled_receivers
768 assert [] == disabled_receivers
772 describe "notification lifecycle" do
773 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
775 other_user = insert(:user)
777 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
779 assert Enum.empty?(Notification.for_user(user))
781 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
783 assert length(Notification.for_user(user)) == 1
785 {:ok, _} = CommonAPI.delete(activity.id, user)
787 assert Enum.empty?(Notification.for_user(user))
790 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
792 other_user = insert(:user)
794 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
796 assert Enum.empty?(Notification.for_user(user))
798 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
800 assert length(Notification.for_user(user)) == 1
802 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
804 assert Enum.empty?(Notification.for_user(user))
807 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
809 other_user = insert(:user)
811 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
813 assert Enum.empty?(Notification.for_user(user))
815 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
817 assert length(Notification.for_user(user)) == 1
819 {:ok, _} = CommonAPI.delete(activity.id, user)
821 assert Enum.empty?(Notification.for_user(user))
824 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
826 other_user = insert(:user)
828 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
830 assert Enum.empty?(Notification.for_user(user))
832 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
834 assert length(Notification.for_user(user)) == 1
836 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
838 assert Enum.empty?(Notification.for_user(user))
841 test "liking an activity which is already deleted does not generate a notification" do
843 other_user = insert(:user)
845 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
847 assert Enum.empty?(Notification.for_user(user))
849 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
851 assert Enum.empty?(Notification.for_user(user))
853 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
855 assert Enum.empty?(Notification.for_user(user))
858 test "repeating an activity which is already deleted does not generate a notification" do
860 other_user = insert(:user)
862 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
864 assert Enum.empty?(Notification.for_user(user))
866 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
868 assert Enum.empty?(Notification.for_user(user))
870 {:error, _} = CommonAPI.repeat(activity.id, other_user)
872 assert Enum.empty?(Notification.for_user(user))
875 test "replying to a deleted post without tagging does not generate a notification" do
877 other_user = insert(:user)
879 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
880 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
882 {:ok, _reply_activity} =
883 CommonAPI.post(other_user, %{
884 status: "test reply",
885 in_reply_to_status_id: activity.id
888 assert Enum.empty?(Notification.for_user(user))
891 test "notifications are deleted if a local user is deleted" do
893 other_user = insert(:user)
896 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
898 refute Enum.empty?(Notification.for_user(other_user))
900 {:ok, job} = User.delete(user)
901 ObanHelpers.perform(job)
903 assert Enum.empty?(Notification.for_user(other_user))
906 test "notifications are deleted if a remote user is deleted" do
907 remote_user = insert(:user)
908 local_user = insert(:user)
911 "@context" => "https://www.w3.org/ns/activitystreams",
913 "actor" => remote_user.ap_id,
914 "id" => remote_user.ap_id <> "/activities/test",
915 "to" => [local_user.ap_id],
919 "content" => "Hello!",
923 "href" => local_user.ap_id,
924 "name" => "@#{local_user.nickname}"
927 "to" => [local_user.ap_id],
929 "attributedTo" => remote_user.ap_id
933 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
935 refute Enum.empty?(Notification.for_user(local_user))
937 delete_user_message = %{
938 "@context" => "https://www.w3.org/ns/activitystreams",
939 "id" => remote_user.ap_id <> "/activities/delete",
940 "actor" => remote_user.ap_id,
942 "object" => remote_user.ap_id
945 remote_user_url = remote_user.ap_id
948 %{method: :get, url: ^remote_user_url} ->
949 %Tesla.Env{status: 404, body: ""}
952 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
953 ObanHelpers.perform_all()
955 assert Enum.empty?(Notification.for_user(local_user))
958 @tag capture_log: true
959 test "move activity generates a notification" do
960 %{ap_id: old_ap_id} = old_user = insert(:user)
961 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
962 follower = insert(:user)
963 other_follower = insert(:user, %{allow_following_move: false})
965 User.follow(follower, old_user)
966 User.follow(other_follower, old_user)
968 old_user_url = old_user.ap_id
971 File.read!("test/fixtures/users_mock/localhost.json")
972 |> String.replace("{{nickname}}", old_user.nickname)
976 %{method: :get, url: ^old_user_url} ->
977 %Tesla.Env{status: 200, body: body}
980 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
981 ObanHelpers.perform_all()
986 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
989 ] = Notification.for_user(follower)
994 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
997 ] = Notification.for_user(other_follower)
1001 describe "for_user" do
1002 test "it returns notifications for muted user without notifications" do
1003 user = insert(:user)
1004 muted = insert(:user)
1005 {:ok, _user_relationships} = User.mute(user, muted, false)
1007 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1009 [notification] = Notification.for_user(user)
1011 assert notification.activity.object
1014 test "it doesn't return notifications for muted user with notifications" do
1015 user = insert(:user)
1016 muted = insert(:user)
1017 {:ok, _user_relationships} = User.mute(user, muted)
1019 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1021 assert Notification.for_user(user) == []
1024 test "it doesn't return notifications for blocked user" do
1025 user = insert(:user)
1026 blocked = insert(:user)
1027 {:ok, _user_relationship} = User.block(user, blocked)
1029 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1031 assert Notification.for_user(user) == []
1034 test "it doesn't return notifications for domain-blocked non-followed user" do
1035 user = insert(:user)
1036 blocked = insert(:user, ap_id: "http://some-domain.com")
1037 {:ok, user} = User.block_domain(user, "some-domain.com")
1039 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1041 assert Notification.for_user(user) == []
1044 test "it returns notifications for domain-blocked but followed user" do
1045 user = insert(:user)
1046 blocked = insert(:user, ap_id: "http://some-domain.com")
1048 {:ok, user} = User.block_domain(user, "some-domain.com")
1049 {:ok, _} = User.follow(user, blocked)
1051 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1053 assert length(Notification.for_user(user)) == 1
1056 test "it doesn't return notifications for muted thread" do
1057 user = insert(:user)
1058 another_user = insert(:user)
1060 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1062 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1063 assert Notification.for_user(user) == []
1066 test "it returns notifications from a muted user when with_muted is set" do
1067 user = insert(:user)
1068 muted = insert(:user)
1069 {:ok, _user_relationships} = User.mute(user, muted)
1071 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1073 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1076 test "it doesn't return notifications from a blocked user when with_muted is set" do
1077 user = insert(:user)
1078 blocked = insert(:user)
1079 {:ok, _user_relationship} = User.block(user, blocked)
1081 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1083 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1086 test "when with_muted is set, " <>
1087 "it doesn't return notifications from a domain-blocked non-followed user" do
1088 user = insert(:user)
1089 blocked = insert(:user, ap_id: "http://some-domain.com")
1090 {:ok, user} = User.block_domain(user, "some-domain.com")
1092 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1094 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1097 test "it returns notifications from muted threads when with_muted is set" do
1098 user = insert(:user)
1099 another_user = insert(:user)
1101 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1103 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1104 assert length(Notification.for_user(user, %{with_muted: true})) == 1