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
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 an emoji reaction" do
37 other_user = insert(:user)
39 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
40 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
42 {:ok, [notification]} = Notification.create_notifications(activity)
44 assert notification.user_id == user.id
45 assert notification.type == "pleroma:emoji_reaction"
48 test "notifies someone when they are directly addressed" do
50 other_user = insert(:user)
51 third_user = insert(:user)
54 CommonAPI.post(user, %{
55 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
58 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
60 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
61 assert notified_ids == [other_user.id, third_user.id]
62 assert notification.activity_id == activity.id
63 assert notification.type == "mention"
64 assert other_notification.activity_id == activity.id
66 assert [%Pleroma.Marker{unread_count: 2}] =
67 Pleroma.Marker.get_markers(other_user, ["notifications"])
70 test "it creates a notification for subscribed users" do
72 subscriber = insert(:user)
74 User.subscribe(subscriber, user)
76 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
77 {:ok, [notification]} = Notification.create_notifications(status)
79 assert notification.user_id == subscriber.id
82 test "does not create a notification for subscribed users if status is a reply" do
84 other_user = insert(:user)
85 subscriber = insert(:user)
87 User.subscribe(subscriber, other_user)
89 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
91 {:ok, _reply_activity} =
92 CommonAPI.post(other_user, %{
94 in_reply_to_status_id: activity.id
97 user_notifications = Notification.for_user(user)
98 assert length(user_notifications) == 1
100 subscriber_notifications = Notification.for_user(subscriber)
101 assert Enum.empty?(subscriber_notifications)
105 describe "CommonApi.post/2 notification-related functionality" do
106 test_with_mock "creates but does NOT send notification to blocker user",
111 blocker = insert(:user)
112 {:ok, _user_relationship} = User.block(blocker, user)
114 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
116 blocker_id = blocker.id
117 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
118 refute called(Push.send(:_))
121 test_with_mock "creates but does NOT send notification to notification-muter user",
126 muter = insert(:user)
127 {:ok, _user_relationships} = User.mute(muter, user)
129 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
132 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
133 refute called(Push.send(:_))
136 test_with_mock "creates but does NOT send notification to thread-muter user",
141 thread_muter = insert(:user)
143 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
145 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
147 {:ok, _same_context_activity} =
148 CommonAPI.post(user, %{
149 status: "hey-hey-hey @#{thread_muter.nickname}!",
150 in_reply_to_status_id: activity.id
153 [pre_mute_notification, post_mute_notification] =
154 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
156 pre_mute_notification_id = pre_mute_notification.id
157 post_mute_notification_id = post_mute_notification.id
162 %Notification{id: ^pre_mute_notification_id} -> true
171 %Notification{id: ^post_mute_notification_id} -> true
179 describe "create_notification" do
180 @tag needs_streamer: true
181 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
182 %{user: user, token: oauth_token} = oauth_access(["read"])
186 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
187 assert_receive {:render_with_user, _, _, _}, 4_000
190 task_user_notification =
193 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
195 assert_receive {:render_with_user, _, _, _}, 4_000
198 activity = insert(:note_activity)
200 notify = Notification.create_notification(activity, user)
201 assert notify.user_id == user.id
203 Task.await(task_user_notification)
206 test "it creates a notification for user if the user blocks the activity author" do
207 activity = insert(:note_activity)
208 author = User.get_cached_by_ap_id(activity.data["actor"])
210 {:ok, _user_relationship} = User.block(user, author)
212 assert Notification.create_notification(activity, user)
215 test "it creates a notification for the user if the user mutes the activity author" do
216 muter = insert(:user)
217 muted = insert(:user)
218 {:ok, _} = User.mute(muter, muted)
219 muter = Repo.get(User, muter.id)
220 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
222 notification = Notification.create_notification(activity, muter)
224 assert notification.id
225 assert notification.seen
228 test "notification created if user is muted without notifications" do
229 muter = insert(:user)
230 muted = insert(:user)
232 {:ok, _user_relationships} = User.mute(muter, muted, false)
234 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
236 assert Notification.create_notification(activity, muter)
239 test "it creates a notification for an activity from a muted thread" do
240 muter = insert(:user)
241 other_user = insert(:user)
242 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
243 CommonAPI.add_mute(muter, activity)
246 CommonAPI.post(other_user, %{
247 status: "Hi @#{muter.nickname}",
248 in_reply_to_status_id: activity.id
251 notification = Notification.create_notification(activity, muter)
253 assert notification.id
254 assert notification.seen
257 test "it disables notifications from strangers" do
258 follower = insert(:user)
262 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
265 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
266 refute Notification.create_notification(activity, followed)
269 test "it doesn't create a notification for user if he is the activity author" do
270 activity = insert(:note_activity)
271 author = User.get_cached_by_ap_id(activity.data["actor"])
273 refute Notification.create_notification(activity, author)
276 test "it doesn't create duplicate notifications for follow+subscribed users" do
278 subscriber = insert(:user)
280 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
281 User.subscribe(subscriber, user)
282 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
283 {:ok, [_notif]} = Notification.create_notifications(status)
286 test "it doesn't create subscription notifications if the recipient cannot see the status" do
288 subscriber = insert(:user)
290 User.subscribe(subscriber, user)
292 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
294 assert {:ok, []} == Notification.create_notifications(status)
297 test "it disables notifications from people who are invisible" do
298 author = insert(:user, invisible: true)
301 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
302 refute Notification.create_notification(status, user)
305 test "it doesn't create notifications if content matches with an irreversible filter" do
307 subscriber = insert(:user)
309 User.subscribe(subscriber, user)
310 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
312 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
314 assert {:ok, []} == Notification.create_notifications(status)
317 test "it creates notifications if content matches with a not irreversible filter" do
319 subscriber = insert(:user)
321 User.subscribe(subscriber, user)
322 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
324 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
325 {:ok, [notification]} = Notification.create_notifications(status)
328 refute notification.seen
331 test "it creates notifications when someone likes user's status with a filtered word" do
333 other_user = insert(:user)
334 insert(:filter, user: user, phrase: "tesla", hide: true)
336 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
337 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
339 {:ok, [notification]} = Notification.create_notifications(activity_two)
342 refute notification.seen
346 describe "follow / follow_request notifications" do
347 test "it creates `follow` notification for approved Follow activity" do
349 followed_user = insert(:user, is_locked: false)
351 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
352 assert FollowingRelationship.following?(user, followed_user)
353 assert [notification] = Notification.for_user(followed_user)
355 assert %{type: "follow"} =
356 NotificationView.render("show.json", %{
357 notification: notification,
362 test "it creates `follow_request` notification for pending Follow activity" do
364 followed_user = insert(:user, is_locked: true)
366 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
367 refute FollowingRelationship.following?(user, followed_user)
368 assert [notification] = Notification.for_user(followed_user)
370 render_opts = %{notification: notification, for: followed_user}
371 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
373 # After request is accepted, the same notification is rendered with type "follow":
374 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
377 Repo.get(Notification, notification.id)
378 |> Repo.preload(:activity)
380 assert %{type: "follow"} =
381 NotificationView.render("show.json", notification: notification, for: followed_user)
384 test "it doesn't create a notification for follow-unfollow-follow chains" do
386 followed_user = insert(:user, is_locked: false)
388 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
389 assert FollowingRelationship.following?(user, followed_user)
390 assert [notification] = Notification.for_user(followed_user)
392 CommonAPI.unfollow(user, followed_user)
393 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
395 notification_id = notification.id
396 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
399 test "dismisses the notification on follow request rejection" do
400 user = insert(:user, is_locked: true)
401 follower = insert(:user)
402 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
403 assert [_notification] = Notification.for_user(user)
404 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
405 assert [] = Notification.for_user(user)
409 describe "get notification" do
410 test "it gets a notification that belongs to the user" do
412 other_user = insert(:user)
414 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
416 {:ok, [notification]} = Notification.create_notifications(activity)
417 {:ok, notification} = Notification.get(other_user, notification.id)
419 assert notification.user_id == other_user.id
422 test "it returns error if the notification doesn't belong to the user" do
424 other_user = insert(:user)
426 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
428 {:ok, [notification]} = Notification.create_notifications(activity)
429 {:error, _notification} = Notification.get(user, notification.id)
433 describe "dismiss notification" do
434 test "it dismisses a notification that belongs to the user" do
436 other_user = insert(:user)
438 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
440 {:ok, [notification]} = Notification.create_notifications(activity)
441 {:ok, notification} = Notification.dismiss(other_user, notification.id)
443 assert notification.user_id == other_user.id
446 test "it returns error if the notification doesn't belong to the user" do
448 other_user = insert(:user)
450 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
452 {:ok, [notification]} = Notification.create_notifications(activity)
453 {:error, _notification} = Notification.dismiss(user, notification.id)
457 describe "clear notification" do
458 test "it clears all notifications belonging to the user" do
460 other_user = insert(:user)
461 third_user = insert(:user)
464 CommonAPI.post(user, %{
465 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
468 {:ok, _notifs} = Notification.create_notifications(activity)
471 CommonAPI.post(user, %{
472 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
475 {:ok, _notifs} = Notification.create_notifications(activity)
476 Notification.clear(other_user)
478 assert Notification.for_user(other_user) == []
479 assert Notification.for_user(third_user) != []
483 describe "set_read_up_to()" do
484 test "it sets all notifications as read up to a specified notification ID" do
486 other_user = insert(:user)
489 CommonAPI.post(user, %{
490 status: "hey @#{other_user.nickname}!"
494 CommonAPI.post(user, %{
495 status: "hey again @#{other_user.nickname}!"
498 [n2, n1] = Notification.for_user(other_user)
503 CommonAPI.post(user, %{
504 status: "hey yet again @#{other_user.nickname}!"
507 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
509 assert read_notification.activity.object
511 [n3, n2, n1] = Notification.for_user(other_user)
513 assert n1.seen == true
514 assert n2.seen == true
515 assert n3.seen == false
517 assert %Pleroma.Marker{} =
521 user_id: other_user.id,
522 timeline: "notifications"
525 assert m.last_read_id == to_string(n2.id)
529 describe "for_user_since/2" do
530 defp days_ago(days) do
532 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
533 -days * 60 * 60 * 24,
538 test "Returns recent notifications" do
539 user1 = insert(:user)
540 user2 = insert(:user)
542 Enum.each(0..10, fn i ->
544 CommonAPI.post(user1, %{
545 status: "hey ##{i} @#{user2.nickname}!"
549 {old, new} = Enum.split(Notification.for_user(user2), 5)
551 Enum.each(old, fn notification ->
553 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
554 |> Pleroma.Repo.update!()
557 recent_notifications_ids =
559 |> Notification.for_user_since(
560 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
564 Enum.each(old, fn %{id: id} ->
565 refute id in recent_notifications_ids
568 Enum.each(new, fn %{id: id} ->
569 assert id in recent_notifications_ids
574 describe "notification target determination / get_notified_from_activity/2" do
575 test "it sends notifications to addressed users in new messages" do
577 other_user = insert(:user)
580 CommonAPI.post(user, %{
581 status: "hey @#{other_user.nickname}!"
584 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
586 assert other_user in enabled_receivers
589 test "it sends notifications to mentioned users in new messages" do
591 other_user = insert(:user)
594 "@context" => "https://www.w3.org/ns/activitystreams",
596 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
597 "actor" => user.ap_id,
600 "content" => "message with a Mention tag, but no explicit tagging",
604 "href" => other_user.ap_id,
605 "name" => other_user.nickname
608 "attributedTo" => user.ap_id
612 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
614 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
616 assert other_user in enabled_receivers
619 test "it does not send notifications to users who are only cc in new messages" do
621 other_user = insert(:user)
624 "@context" => "https://www.w3.org/ns/activitystreams",
626 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
627 "cc" => [other_user.ap_id],
628 "actor" => user.ap_id,
631 "content" => "hi everyone",
632 "attributedTo" => user.ap_id
636 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
638 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
640 assert other_user not in enabled_receivers
643 test "it does not send notification to mentioned users in likes" do
645 other_user = insert(:user)
646 third_user = insert(:user)
648 {:ok, activity_one} =
649 CommonAPI.post(user, %{
650 status: "hey @#{other_user.nickname}!"
653 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
655 {enabled_receivers, _disabled_receivers} =
656 Notification.get_notified_from_activity(activity_two)
658 assert other_user not in enabled_receivers
661 test "it only notifies the post's author in likes" do
663 other_user = insert(:user)
664 third_user = insert(:user)
666 {:ok, activity_one} =
667 CommonAPI.post(user, %{
668 status: "hey @#{other_user.nickname}!"
671 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
675 |> Map.put("to", [other_user.ap_id | like_data["to"]])
676 |> ActivityPub.persist(local: true)
678 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
680 assert other_user not in enabled_receivers
683 test "it does not send notification to mentioned users in announces" 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.repeat(activity_one.id, third_user)
695 {enabled_receivers, _disabled_receivers} =
696 Notification.get_notified_from_activity(activity_two)
698 assert other_user not in enabled_receivers
701 test "it returns blocking recipient in disabled recipients list" do
703 other_user = insert(:user)
704 {:ok, _user_relationship} = User.block(other_user, user)
706 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
708 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
710 assert [] == enabled_receivers
711 assert [other_user] == disabled_receivers
714 test "it returns notification-muting recipient in disabled recipients list" do
716 other_user = insert(:user)
717 {:ok, _user_relationships} = User.mute(other_user, user)
719 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
721 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
723 assert [] == enabled_receivers
724 assert [other_user] == disabled_receivers
727 test "it returns thread-muting recipient in disabled recipients list" do
729 other_user = insert(:user)
731 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
733 {:ok, _} = CommonAPI.add_mute(other_user, activity)
735 {:ok, same_context_activity} =
736 CommonAPI.post(user, %{
737 status: "hey-hey-hey @#{other_user.nickname}!",
738 in_reply_to_status_id: activity.id
741 {enabled_receivers, disabled_receivers} =
742 Notification.get_notified_from_activity(same_context_activity)
744 assert [other_user] == disabled_receivers
745 refute other_user in enabled_receivers
748 test "it returns non-following domain-blocking recipient in disabled recipients list" do
749 blocked_domain = "blocked.domain"
750 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
751 other_user = insert(:user)
753 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
755 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
757 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
759 assert [] == enabled_receivers
760 assert [other_user] == disabled_receivers
763 test "it returns following domain-blocking recipient in enabled recipients list" do
764 blocked_domain = "blocked.domain"
765 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
766 other_user = insert(:user)
768 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
769 {:ok, other_user} = User.follow(other_user, user)
771 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
773 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
775 assert [other_user] == enabled_receivers
776 assert [] == disabled_receivers
780 describe "notification lifecycle" do
781 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
783 other_user = insert(:user)
785 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
787 assert Enum.empty?(Notification.for_user(user))
789 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
791 assert length(Notification.for_user(user)) == 1
793 {:ok, _} = CommonAPI.delete(activity.id, user)
795 assert Enum.empty?(Notification.for_user(user))
798 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
800 other_user = insert(:user)
802 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
804 assert Enum.empty?(Notification.for_user(user))
806 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
808 assert length(Notification.for_user(user)) == 1
810 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
812 assert Enum.empty?(Notification.for_user(user))
815 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
817 other_user = insert(:user)
819 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
821 assert Enum.empty?(Notification.for_user(user))
823 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
825 assert length(Notification.for_user(user)) == 1
827 {:ok, _} = CommonAPI.delete(activity.id, user)
829 assert Enum.empty?(Notification.for_user(user))
832 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
834 other_user = insert(:user)
836 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
838 assert Enum.empty?(Notification.for_user(user))
840 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
842 assert length(Notification.for_user(user)) == 1
844 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
846 assert Enum.empty?(Notification.for_user(user))
849 test "liking an activity which is already deleted does not generate a notification" do
851 other_user = insert(:user)
853 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
855 assert Enum.empty?(Notification.for_user(user))
857 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
859 assert Enum.empty?(Notification.for_user(user))
861 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
863 assert Enum.empty?(Notification.for_user(user))
866 test "repeating an activity which is already deleted does not generate a notification" do
868 other_user = insert(:user)
870 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
872 assert Enum.empty?(Notification.for_user(user))
874 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
876 assert Enum.empty?(Notification.for_user(user))
878 {:error, _} = CommonAPI.repeat(activity.id, other_user)
880 assert Enum.empty?(Notification.for_user(user))
883 test "replying to a deleted post without tagging does not generate a notification" do
885 other_user = insert(:user)
887 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
888 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
890 {:ok, _reply_activity} =
891 CommonAPI.post(other_user, %{
892 status: "test reply",
893 in_reply_to_status_id: activity.id
896 assert Enum.empty?(Notification.for_user(user))
899 test "notifications are deleted if a local user is deleted" do
901 other_user = insert(:user)
904 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
906 refute Enum.empty?(Notification.for_user(other_user))
908 {:ok, job} = User.delete(user)
909 ObanHelpers.perform(job)
911 assert Enum.empty?(Notification.for_user(other_user))
914 test "notifications are deleted if a remote user is deleted" do
915 remote_user = insert(:user)
916 local_user = insert(:user)
919 "@context" => "https://www.w3.org/ns/activitystreams",
921 "actor" => remote_user.ap_id,
922 "id" => remote_user.ap_id <> "/activities/test",
923 "to" => [local_user.ap_id],
927 "content" => "Hello!",
931 "href" => local_user.ap_id,
932 "name" => "@#{local_user.nickname}"
935 "to" => [local_user.ap_id],
937 "attributedTo" => remote_user.ap_id
941 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
943 refute Enum.empty?(Notification.for_user(local_user))
945 delete_user_message = %{
946 "@context" => "https://www.w3.org/ns/activitystreams",
947 "id" => remote_user.ap_id <> "/activities/delete",
948 "actor" => remote_user.ap_id,
950 "object" => remote_user.ap_id
953 remote_user_url = remote_user.ap_id
956 %{method: :get, url: ^remote_user_url} ->
957 %Tesla.Env{status: 404, body: ""}
960 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
961 ObanHelpers.perform_all()
963 assert Enum.empty?(Notification.for_user(local_user))
966 @tag capture_log: true
967 test "move activity generates a notification" do
968 %{ap_id: old_ap_id} = old_user = insert(:user)
969 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
970 follower = insert(:user)
971 other_follower = insert(:user, %{allow_following_move: false})
973 User.follow(follower, old_user)
974 User.follow(other_follower, old_user)
976 old_user_url = old_user.ap_id
979 File.read!("test/fixtures/users_mock/localhost.json")
980 |> String.replace("{{nickname}}", old_user.nickname)
984 %{method: :get, url: ^old_user_url} ->
985 %Tesla.Env{status: 200, body: body}
988 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
989 ObanHelpers.perform_all()
994 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
997 ] = Notification.for_user(follower)
1002 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1005 ] = Notification.for_user(other_follower)
1009 describe "for_user" do
1011 user = insert(:user)
1013 {:ok, %{user: user}}
1016 test "it returns notifications for muted user without notifications", %{user: user} do
1017 muted = insert(:user)
1018 {:ok, _user_relationships} = User.mute(user, muted, false)
1020 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1022 [notification] = Notification.for_user(user)
1024 assert notification.activity.object
1025 assert notification.seen
1028 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1029 muted = insert(:user)
1030 {:ok, _user_relationships} = User.mute(user, muted)
1032 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1034 assert Notification.for_user(user) == []
1037 test "it doesn't return notifications for blocked user", %{user: user} do
1038 blocked = insert(:user)
1039 {:ok, _user_relationship} = User.block(user, blocked)
1041 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1043 assert Notification.for_user(user) == []
1046 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1047 blocked = insert(:user, ap_id: "http://some-domain.com")
1048 {:ok, user} = User.block_domain(user, "some-domain.com")
1050 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1052 assert Notification.for_user(user) == []
1055 test "it returns notifications for domain-blocked but followed user" do
1056 user = insert(:user)
1057 blocked = insert(:user, ap_id: "http://some-domain.com")
1059 {:ok, user} = User.block_domain(user, "some-domain.com")
1060 {:ok, _} = User.follow(user, blocked)
1062 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1064 assert length(Notification.for_user(user)) == 1
1067 test "it doesn't return notifications for muted thread", %{user: user} do
1068 another_user = insert(:user)
1070 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1072 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1073 assert Notification.for_user(user) == []
1076 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1077 muted = insert(:user)
1078 {:ok, _user_relationships} = User.mute(user, muted)
1080 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1082 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1085 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1088 blocked = insert(:user)
1089 {:ok, _user_relationship} = User.block(user, blocked)
1091 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1093 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1096 test "when with_muted is set, " <>
1097 "it doesn't return notifications from a domain-blocked non-followed user",
1099 blocked = insert(:user, ap_id: "http://some-domain.com")
1100 {:ok, user} = User.block_domain(user, "some-domain.com")
1102 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1104 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1107 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1108 another_user = insert(:user)
1110 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1112 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1113 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1116 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1117 insert(:filter, user: user, phrase: "cofe", hide: true)
1118 another_user = insert(:user)
1120 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1122 assert Enum.empty?(Notification.for_user(user))
1125 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1126 insert(:filter, user: user, phrase: "test", hide: false)
1127 another_user = insert(:user)
1129 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1131 assert length(Notification.for_user(user)) == 1
1134 test "it returns notifications about favorites with filtered word", %{user: user} do
1135 insert(:filter, user: user, phrase: "cofe", hide: true)
1136 another_user = insert(:user)
1138 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1139 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1141 assert length(Notification.for_user(user)) == 1