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 a report" do
36 reporting_user = insert(:user)
37 reported_user = insert(:user)
38 {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true})
40 {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
42 {:ok, [notification]} = Notification.create_notifications(activity)
44 assert notification.user_id == moderator_user.id
45 assert notification.type == "pleroma:report"
48 test "creates a notification for an emoji reaction" do
50 other_user = insert(:user)
52 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
53 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
55 {:ok, [notification]} = Notification.create_notifications(activity)
57 assert notification.user_id == user.id
58 assert notification.type == "pleroma:emoji_reaction"
61 test "notifies someone when they are directly addressed" do
63 other_user = insert(:user)
64 third_user = insert(:user)
67 CommonAPI.post(user, %{
68 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
71 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
73 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
74 assert notified_ids == [other_user.id, third_user.id]
75 assert notification.activity_id == activity.id
76 assert notification.type == "mention"
77 assert other_notification.activity_id == activity.id
79 assert [%Pleroma.Marker{unread_count: 2}] =
80 Pleroma.Marker.get_markers(other_user, ["notifications"])
83 test "it creates a notification for subscribed users" do
85 subscriber = insert(:user)
87 User.subscribe(subscriber, user)
89 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
90 {:ok, [notification]} = Notification.create_notifications(status)
92 assert notification.user_id == subscriber.id
95 test "does not create a notification for subscribed users if status is a reply" do
97 other_user = insert(:user)
98 subscriber = insert(:user)
100 User.subscribe(subscriber, other_user)
102 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
104 {:ok, _reply_activity} =
105 CommonAPI.post(other_user, %{
106 status: "test reply",
107 in_reply_to_status_id: activity.id
110 user_notifications = Notification.for_user(user)
111 assert length(user_notifications) == 1
113 subscriber_notifications = Notification.for_user(subscriber)
114 assert Enum.empty?(subscriber_notifications)
118 describe "CommonApi.post/2 notification-related functionality" do
119 test_with_mock "creates but does NOT send notification to blocker user",
124 blocker = insert(:user)
125 {:ok, _user_relationship} = User.block(blocker, user)
127 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
129 blocker_id = blocker.id
130 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
131 refute called(Push.send(:_))
134 test_with_mock "creates but does NOT send notification to notification-muter user",
139 muter = insert(:user)
140 {:ok, _user_relationships} = User.mute(muter, user)
142 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
145 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
146 refute called(Push.send(:_))
149 test_with_mock "creates but does NOT send notification to thread-muter user",
154 thread_muter = insert(:user)
156 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
158 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
160 {:ok, _same_context_activity} =
161 CommonAPI.post(user, %{
162 status: "hey-hey-hey @#{thread_muter.nickname}!",
163 in_reply_to_status_id: activity.id
166 [pre_mute_notification, post_mute_notification] =
167 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
169 pre_mute_notification_id = pre_mute_notification.id
170 post_mute_notification_id = post_mute_notification.id
175 %Notification{id: ^pre_mute_notification_id} -> true
184 %Notification{id: ^post_mute_notification_id} -> true
192 describe "create_notification" do
193 @tag needs_streamer: true
194 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
195 %{user: user, token: oauth_token} = oauth_access(["read"])
199 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
200 assert_receive {:render_with_user, _, _, _}, 4_000
203 task_user_notification =
206 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
208 assert_receive {:render_with_user, _, _, _}, 4_000
211 activity = insert(:note_activity)
213 notify = Notification.create_notification(activity, user)
214 assert notify.user_id == user.id
216 Task.await(task_user_notification)
219 test "it creates a notification for user if the user blocks the activity author" do
220 activity = insert(:note_activity)
221 author = User.get_cached_by_ap_id(activity.data["actor"])
223 {:ok, _user_relationship} = User.block(user, author)
225 assert Notification.create_notification(activity, user)
228 test "it creates a notification for the user if the user mutes the activity author" do
229 muter = insert(:user)
230 muted = insert(:user)
231 {:ok, _} = User.mute(muter, muted)
232 muter = Repo.get(User, muter.id)
233 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
235 notification = Notification.create_notification(activity, muter)
237 assert notification.id
238 assert notification.seen
241 test "notification created if user is muted without notifications" do
242 muter = insert(:user)
243 muted = insert(:user)
245 {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
247 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
249 assert Notification.create_notification(activity, muter)
252 test "it creates a notification for an activity from a muted thread" do
253 muter = insert(:user)
254 other_user = insert(:user)
255 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
256 CommonAPI.add_mute(muter, activity)
259 CommonAPI.post(other_user, %{
260 status: "Hi @#{muter.nickname}",
261 in_reply_to_status_id: activity.id
264 notification = Notification.create_notification(activity, muter)
266 assert notification.id
267 assert notification.seen
270 test "it disables notifications from strangers" do
271 follower = insert(:user)
275 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
278 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
279 refute Notification.create_notification(activity, followed)
282 test "it doesn't create a notification for user if he is the activity author" do
283 activity = insert(:note_activity)
284 author = User.get_cached_by_ap_id(activity.data["actor"])
286 refute Notification.create_notification(activity, author)
289 test "it doesn't create duplicate notifications for follow+subscribed users" do
291 subscriber = insert(:user)
293 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
294 User.subscribe(subscriber, user)
295 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
296 {:ok, [_notif]} = Notification.create_notifications(status)
299 test "it doesn't create subscription notifications if the recipient cannot see the status" do
301 subscriber = insert(:user)
303 User.subscribe(subscriber, user)
305 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
307 assert {:ok, []} == Notification.create_notifications(status)
310 test "it disables notifications from people who are invisible" do
311 author = insert(:user, invisible: true)
314 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
315 refute Notification.create_notification(status, user)
318 test "it doesn't create notifications if content matches with an irreversible filter" do
320 subscriber = insert(:user)
322 User.subscribe(subscriber, user)
323 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
325 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
327 assert {:ok, []} == Notification.create_notifications(status)
330 test "it creates notifications if content matches with a not irreversible filter" do
332 subscriber = insert(:user)
334 User.subscribe(subscriber, user)
335 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
337 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
338 {:ok, [notification]} = Notification.create_notifications(status)
341 refute notification.seen
344 test "it creates notifications when someone likes user's status with a filtered word" do
346 other_user = insert(:user)
347 insert(:filter, user: user, phrase: "tesla", hide: true)
349 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
350 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
352 {:ok, [notification]} = Notification.create_notifications(activity_two)
355 refute notification.seen
359 describe "follow / follow_request notifications" do
360 test "it creates `follow` notification for approved Follow activity" do
362 followed_user = insert(:user, is_locked: false)
364 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
365 assert FollowingRelationship.following?(user, followed_user)
366 assert [notification] = Notification.for_user(followed_user)
368 assert %{type: "follow"} =
369 NotificationView.render("show.json", %{
370 notification: notification,
375 test "it creates `follow_request` notification for pending Follow activity" do
377 followed_user = insert(:user, is_locked: true)
379 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
380 refute FollowingRelationship.following?(user, followed_user)
381 assert [notification] = Notification.for_user(followed_user)
383 render_opts = %{notification: notification, for: followed_user}
384 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
386 # After request is accepted, the same notification is rendered with type "follow":
387 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
390 Repo.get(Notification, notification.id)
391 |> Repo.preload(:activity)
393 assert %{type: "follow"} =
394 NotificationView.render("show.json", notification: notification, for: followed_user)
397 test "it doesn't create a notification for follow-unfollow-follow chains" do
399 followed_user = insert(:user, is_locked: false)
401 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
402 assert FollowingRelationship.following?(user, followed_user)
403 assert [notification] = Notification.for_user(followed_user)
405 CommonAPI.unfollow(user, followed_user)
406 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
408 notification_id = notification.id
409 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
412 test "dismisses the notification on follow request rejection" do
413 user = insert(:user, is_locked: true)
414 follower = insert(:user)
415 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
416 assert [_notification] = Notification.for_user(user)
417 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
418 assert [] = Notification.for_user(user)
422 describe "get notification" do
423 test "it gets a notification that belongs to the user" do
425 other_user = insert(:user)
427 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
429 {:ok, [notification]} = Notification.create_notifications(activity)
430 {:ok, notification} = Notification.get(other_user, notification.id)
432 assert notification.user_id == other_user.id
435 test "it returns error if the notification doesn't belong to the user" do
437 other_user = insert(:user)
439 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
441 {:ok, [notification]} = Notification.create_notifications(activity)
442 {:error, _notification} = Notification.get(user, notification.id)
446 describe "dismiss notification" do
447 test "it dismisses a notification that belongs to the user" do
449 other_user = insert(:user)
451 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
453 {:ok, [notification]} = Notification.create_notifications(activity)
454 {:ok, notification} = Notification.dismiss(other_user, notification.id)
456 assert notification.user_id == other_user.id
459 test "it returns error if the notification doesn't belong to the user" do
461 other_user = insert(:user)
463 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
465 {:ok, [notification]} = Notification.create_notifications(activity)
466 {:error, _notification} = Notification.dismiss(user, notification.id)
470 describe "clear notification" do
471 test "it clears all notifications belonging to the user" do
473 other_user = insert(:user)
474 third_user = insert(:user)
477 CommonAPI.post(user, %{
478 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
481 {:ok, _notifs} = Notification.create_notifications(activity)
484 CommonAPI.post(user, %{
485 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
488 {:ok, _notifs} = Notification.create_notifications(activity)
489 Notification.clear(other_user)
491 assert Notification.for_user(other_user) == []
492 assert Notification.for_user(third_user) != []
496 describe "set_read_up_to()" do
497 test "it sets all notifications as read up to a specified notification ID" do
499 other_user = insert(:user)
502 CommonAPI.post(user, %{
503 status: "hey @#{other_user.nickname}!"
507 CommonAPI.post(user, %{
508 status: "hey again @#{other_user.nickname}!"
511 [n2, n1] = Notification.for_user(other_user)
516 CommonAPI.post(user, %{
517 status: "hey yet again @#{other_user.nickname}!"
520 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
522 assert read_notification.activity.object
524 [n3, n2, n1] = Notification.for_user(other_user)
526 assert n1.seen == true
527 assert n2.seen == true
528 assert n3.seen == false
530 assert %Pleroma.Marker{} =
534 user_id: other_user.id,
535 timeline: "notifications"
538 assert m.last_read_id == to_string(n2.id)
542 describe "for_user_since/2" do
543 defp days_ago(days) do
545 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
546 -days * 60 * 60 * 24,
551 test "Returns recent notifications" do
552 user1 = insert(:user)
553 user2 = insert(:user)
555 Enum.each(0..10, fn i ->
557 CommonAPI.post(user1, %{
558 status: "hey ##{i} @#{user2.nickname}!"
562 {old, new} = Enum.split(Notification.for_user(user2), 5)
564 Enum.each(old, fn notification ->
566 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
567 |> Pleroma.Repo.update!()
570 recent_notifications_ids =
572 |> Notification.for_user_since(
573 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
577 Enum.each(old, fn %{id: id} ->
578 refute id in recent_notifications_ids
581 Enum.each(new, fn %{id: id} ->
582 assert id in recent_notifications_ids
587 describe "notification target determination / get_notified_from_activity/2" do
588 test "it sends notifications to addressed users in new messages" do
590 other_user = insert(:user)
593 CommonAPI.post(user, %{
594 status: "hey @#{other_user.nickname}!"
597 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
599 assert other_user in enabled_receivers
602 test "it sends notifications to mentioned users in new messages" do
604 other_user = insert(:user)
607 "@context" => "https://www.w3.org/ns/activitystreams",
609 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
610 "actor" => user.ap_id,
613 "content" => "message with a Mention tag, but no explicit tagging",
617 "href" => other_user.ap_id,
618 "name" => other_user.nickname
621 "attributedTo" => user.ap_id
625 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
627 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
629 assert other_user in enabled_receivers
632 test "it does not send notifications to users who are only cc in new messages" do
634 other_user = insert(:user)
637 "@context" => "https://www.w3.org/ns/activitystreams",
639 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
640 "cc" => [other_user.ap_id],
641 "actor" => user.ap_id,
644 "content" => "hi everyone",
645 "attributedTo" => user.ap_id
649 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
651 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
653 assert other_user not in enabled_receivers
656 test "it does not send notification to mentioned users in likes" do
658 other_user = insert(:user)
659 third_user = insert(:user)
661 {:ok, activity_one} =
662 CommonAPI.post(user, %{
663 status: "hey @#{other_user.nickname}!"
666 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
668 {enabled_receivers, _disabled_receivers} =
669 Notification.get_notified_from_activity(activity_two)
671 assert other_user not in enabled_receivers
674 test "it only notifies the post's author in likes" do
676 other_user = insert(:user)
677 third_user = insert(:user)
679 {:ok, activity_one} =
680 CommonAPI.post(user, %{
681 status: "hey @#{other_user.nickname}!"
684 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
688 |> Map.put("to", [other_user.ap_id | like_data["to"]])
689 |> ActivityPub.persist(local: true)
691 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
693 assert other_user not in enabled_receivers
696 test "it does not send notification to mentioned users in announces" do
698 other_user = insert(:user)
699 third_user = insert(:user)
701 {:ok, activity_one} =
702 CommonAPI.post(user, %{
703 status: "hey @#{other_user.nickname}!"
706 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
708 {enabled_receivers, _disabled_receivers} =
709 Notification.get_notified_from_activity(activity_two)
711 assert other_user not in enabled_receivers
714 test "it returns blocking recipient in disabled recipients list" do
716 other_user = insert(:user)
717 {:ok, _user_relationship} = User.block(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 notification-muting recipient in disabled recipients list" do
729 other_user = insert(:user)
730 {:ok, _user_relationships} = User.mute(other_user, user)
732 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
734 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
736 assert [] == enabled_receivers
737 assert [other_user] == disabled_receivers
740 test "it returns thread-muting recipient in disabled recipients list" do
742 other_user = insert(:user)
744 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
746 {:ok, _} = CommonAPI.add_mute(other_user, activity)
748 {:ok, same_context_activity} =
749 CommonAPI.post(user, %{
750 status: "hey-hey-hey @#{other_user.nickname}!",
751 in_reply_to_status_id: activity.id
754 {enabled_receivers, disabled_receivers} =
755 Notification.get_notified_from_activity(same_context_activity)
757 assert [other_user] == disabled_receivers
758 refute other_user in enabled_receivers
761 test "it returns non-following domain-blocking recipient in disabled recipients list" do
762 blocked_domain = "blocked.domain"
763 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
764 other_user = insert(:user)
766 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
768 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
770 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
772 assert [] == enabled_receivers
773 assert [other_user] == disabled_receivers
776 test "it returns following domain-blocking recipient in enabled recipients list" do
777 blocked_domain = "blocked.domain"
778 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
779 other_user = insert(:user)
781 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
782 {:ok, other_user} = User.follow(other_user, user)
784 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
786 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
788 assert [other_user] == enabled_receivers
789 assert [] == disabled_receivers
793 describe "notification lifecycle" do
794 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
796 other_user = insert(:user)
798 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
800 assert Enum.empty?(Notification.for_user(user))
802 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
804 assert length(Notification.for_user(user)) == 1
806 {:ok, _} = CommonAPI.delete(activity.id, user)
808 assert Enum.empty?(Notification.for_user(user))
811 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
813 other_user = insert(:user)
815 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
817 assert Enum.empty?(Notification.for_user(user))
819 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
821 assert length(Notification.for_user(user)) == 1
823 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
825 assert Enum.empty?(Notification.for_user(user))
828 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
830 other_user = insert(:user)
832 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
834 assert Enum.empty?(Notification.for_user(user))
836 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
838 assert length(Notification.for_user(user)) == 1
840 {:ok, _} = CommonAPI.delete(activity.id, user)
842 assert Enum.empty?(Notification.for_user(user))
845 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
847 other_user = insert(:user)
849 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
851 assert Enum.empty?(Notification.for_user(user))
853 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
855 assert length(Notification.for_user(user)) == 1
857 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
859 assert Enum.empty?(Notification.for_user(user))
862 test "liking an activity which is already deleted does not generate a notification" do
864 other_user = insert(:user)
866 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
868 assert Enum.empty?(Notification.for_user(user))
870 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
872 assert Enum.empty?(Notification.for_user(user))
874 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
876 assert Enum.empty?(Notification.for_user(user))
879 test "repeating an activity which is already deleted does not generate a notification" do
881 other_user = insert(:user)
883 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
885 assert Enum.empty?(Notification.for_user(user))
887 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
889 assert Enum.empty?(Notification.for_user(user))
891 {:error, _} = CommonAPI.repeat(activity.id, other_user)
893 assert Enum.empty?(Notification.for_user(user))
896 test "replying to a deleted post without tagging does not generate a notification" do
898 other_user = insert(:user)
900 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
901 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
903 {:ok, _reply_activity} =
904 CommonAPI.post(other_user, %{
905 status: "test reply",
906 in_reply_to_status_id: activity.id
909 assert Enum.empty?(Notification.for_user(user))
912 test "notifications are deleted if a local user is deleted" do
914 other_user = insert(:user)
917 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
919 refute Enum.empty?(Notification.for_user(other_user))
921 {:ok, job} = User.delete(user)
922 ObanHelpers.perform(job)
924 assert Enum.empty?(Notification.for_user(other_user))
927 test "notifications are deleted if a remote user is deleted" do
928 remote_user = insert(:user)
929 local_user = insert(:user)
932 "@context" => "https://www.w3.org/ns/activitystreams",
934 "actor" => remote_user.ap_id,
935 "id" => remote_user.ap_id <> "/activities/test",
936 "to" => [local_user.ap_id],
940 "content" => "Hello!",
944 "href" => local_user.ap_id,
945 "name" => "@#{local_user.nickname}"
948 "to" => [local_user.ap_id],
950 "attributedTo" => remote_user.ap_id
954 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
956 refute Enum.empty?(Notification.for_user(local_user))
958 delete_user_message = %{
959 "@context" => "https://www.w3.org/ns/activitystreams",
960 "id" => remote_user.ap_id <> "/activities/delete",
961 "actor" => remote_user.ap_id,
963 "object" => remote_user.ap_id
966 remote_user_url = remote_user.ap_id
969 %{method: :get, url: ^remote_user_url} ->
970 %Tesla.Env{status: 404, body: ""}
973 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
974 ObanHelpers.perform_all()
976 assert Enum.empty?(Notification.for_user(local_user))
979 @tag capture_log: true
980 test "move activity generates a notification" do
981 %{ap_id: old_ap_id} = old_user = insert(:user)
982 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
983 follower = insert(:user)
984 other_follower = insert(:user, %{allow_following_move: false})
986 User.follow(follower, old_user)
987 User.follow(other_follower, old_user)
989 old_user_url = old_user.ap_id
992 File.read!("test/fixtures/users_mock/localhost.json")
993 |> String.replace("{{nickname}}", old_user.nickname)
997 %{method: :get, url: ^old_user_url} ->
998 %Tesla.Env{status: 200, body: body}
1001 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1002 ObanHelpers.perform_all()
1007 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1010 ] = Notification.for_user(follower)
1015 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1018 ] = Notification.for_user(other_follower)
1022 describe "for_user" do
1024 user = insert(:user)
1026 {:ok, %{user: user}}
1029 test "it returns notifications for muted user without notifications", %{user: user} do
1030 muted = insert(:user)
1031 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1033 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1035 [notification] = Notification.for_user(user)
1037 assert notification.activity.object
1038 assert notification.seen
1041 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1042 muted = insert(:user)
1043 {:ok, _user_relationships} = User.mute(user, muted)
1045 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1047 assert Notification.for_user(user) == []
1050 test "it doesn't return notifications for blocked user", %{user: user} do
1051 blocked = insert(:user)
1052 {:ok, _user_relationship} = User.block(user, blocked)
1054 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1056 assert Notification.for_user(user) == []
1059 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1060 blocked = insert(:user, ap_id: "http://some-domain.com")
1061 {:ok, user} = User.block_domain(user, "some-domain.com")
1063 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1065 assert Notification.for_user(user) == []
1068 test "it returns notifications for domain-blocked but followed user" do
1069 user = insert(:user)
1070 blocked = insert(:user, ap_id: "http://some-domain.com")
1072 {:ok, user} = User.block_domain(user, "some-domain.com")
1073 {:ok, _} = User.follow(user, blocked)
1075 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1077 assert length(Notification.for_user(user)) == 1
1080 test "it doesn't return notifications for muted thread", %{user: user} do
1081 another_user = insert(:user)
1083 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1085 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1086 assert Notification.for_user(user) == []
1089 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1090 muted = insert(:user)
1091 {:ok, _user_relationships} = User.mute(user, muted)
1093 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1095 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1098 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1101 blocked = insert(:user)
1102 {:ok, _user_relationship} = User.block(user, blocked)
1104 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1106 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1109 test "when with_muted is set, " <>
1110 "it doesn't return notifications from a domain-blocked non-followed user",
1112 blocked = insert(:user, ap_id: "http://some-domain.com")
1113 {:ok, user} = User.block_domain(user, "some-domain.com")
1115 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1117 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1120 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1121 another_user = insert(:user)
1123 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1125 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1126 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1129 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1130 insert(:filter, user: user, phrase: "cofe", hide: true)
1131 another_user = insert(:user)
1133 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1135 assert Enum.empty?(Notification.for_user(user))
1138 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1139 insert(:filter, user: user, phrase: "test", hide: false)
1140 another_user = insert(:user)
1142 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1144 assert length(Notification.for_user(user)) == 1
1147 test "it returns notifications about favorites with filtered word", %{user: user} do
1148 insert(:filter, user: user, phrase: "cofe", hide: true)
1149 another_user = insert(:user)
1151 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1152 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1154 assert length(Notification.for_user(user)) == 1