1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.NotificationTest do
11 alias Pleroma.FollowingRelationship
12 alias Pleroma.Notification
14 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.ActivityPub.Builder
18 alias Pleroma.Web.ActivityPub.Transmogrifier
19 alias Pleroma.Web.CommonAPI
20 alias Pleroma.Web.MastodonAPI.NotificationView
21 alias Pleroma.Web.Push
22 alias Pleroma.Web.Streamer
24 describe "create_notifications" do
25 test "never returns nil" do
27 other_user = insert(:user, %{invisible: true})
29 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
30 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
32 refute {:ok, [nil]} == Notification.create_notifications(activity)
35 test "creates a notification for a report" do
36 reporting_user = insert(:user)
37 reported_user = insert(:user)
38 {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true})
40 {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
42 {:ok, [notification]} = Notification.create_notifications(activity)
44 assert notification.user_id == moderator_user.id
45 assert notification.type == "pleroma:report"
48 test "suppresses notification to reporter if reporter is an admin" do
49 reporting_admin = insert(:user, is_admin: true)
50 reported_user = insert(:user)
51 other_admin = insert(:user, is_admin: true)
53 {:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id})
55 {:ok, [notification]} = Notification.create_notifications(activity)
57 refute notification.user_id == reporting_admin.id
58 assert notification.user_id == other_admin.id
59 assert notification.type == "pleroma:report"
62 test "creates a notification for an emoji reaction" do
64 other_user = insert(:user)
66 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
67 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
69 {:ok, [notification]} = Notification.create_notifications(activity)
71 assert notification.user_id == user.id
72 assert notification.type == "pleroma:emoji_reaction"
75 test "notifies someone when they are directly addressed" do
77 other_user = insert(:user)
78 third_user = insert(:user)
81 CommonAPI.post(user, %{
82 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
85 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
87 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
88 assert notified_ids == [other_user.id, third_user.id]
89 assert notification.activity_id == activity.id
90 assert notification.type == "mention"
91 assert other_notification.activity_id == activity.id
93 assert [%Pleroma.Marker{unread_count: 2}] =
94 Pleroma.Marker.get_markers(other_user, ["notifications"])
97 test "it creates a notification for subscribed users" do
99 subscriber = insert(:user)
101 User.subscribe(subscriber, user)
103 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
104 {:ok, [notification]} = Notification.create_notifications(status)
106 assert notification.user_id == subscriber.id
109 test "does not create a notification for subscribed users if status is a reply" do
111 other_user = insert(:user)
112 subscriber = insert(:user)
114 User.subscribe(subscriber, other_user)
116 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
118 {:ok, _reply_activity} =
119 CommonAPI.post(other_user, %{
120 status: "test reply",
121 in_reply_to_status_id: activity.id
124 user_notifications = Notification.for_user(user)
125 assert length(user_notifications) == 1
127 subscriber_notifications = Notification.for_user(subscriber)
128 assert Enum.empty?(subscriber_notifications)
132 test "create_poll_notifications/1" do
133 [user1, user2, user3, _, _] = insert_list(5, :user)
134 question = insert(:question, user: user1)
135 activity = insert(:question_activity, question: question)
137 {:ok, _, _} = CommonAPI.vote(user2, question, [0])
138 {:ok, _, _} = CommonAPI.vote(user3, question, [1])
140 {:ok, notifications} = Notification.create_poll_notifications(activity)
142 assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
145 describe "CommonApi.post/2 notification-related functionality" do
146 test_with_mock "creates but does NOT send notification to blocker user",
151 blocker = insert(:user)
152 {:ok, _user_relationship} = User.block(blocker, user)
154 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
156 blocker_id = blocker.id
157 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
158 refute called(Push.send(:_))
161 test_with_mock "creates but does NOT send notification to notification-muter user",
166 muter = insert(:user)
167 {:ok, _user_relationships} = User.mute(muter, user)
169 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
172 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
173 refute called(Push.send(:_))
176 test_with_mock "creates but does NOT send notification to thread-muter user",
181 thread_muter = insert(:user)
183 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
185 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
187 {:ok, _same_context_activity} =
188 CommonAPI.post(user, %{
189 status: "hey-hey-hey @#{thread_muter.nickname}!",
190 in_reply_to_status_id: activity.id
193 [pre_mute_notification, post_mute_notification] =
194 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
196 pre_mute_notification_id = pre_mute_notification.id
197 post_mute_notification_id = post_mute_notification.id
202 %Notification{id: ^pre_mute_notification_id} -> true
211 %Notification{id: ^post_mute_notification_id} -> true
219 describe "create_notification" do
220 @tag needs_streamer: true
221 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
222 %{user: user, token: oauth_token} = oauth_access(["read"])
226 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
227 assert_receive {:render_with_user, _, _, _}, 4_000
230 task_user_notification =
233 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
235 assert_receive {:render_with_user, _, _, _}, 4_000
238 activity = insert(:note_activity)
240 notify = Notification.create_notification(activity, user)
241 assert notify.user_id == user.id
243 Task.await(task_user_notification)
246 test "it creates a notification for user if the user blocks the activity author" do
247 activity = insert(:note_activity)
248 author = User.get_cached_by_ap_id(activity.data["actor"])
250 {:ok, _user_relationship} = User.block(user, author)
252 assert Notification.create_notification(activity, user)
255 test "it creates a notification for the user if the user mutes the activity author" do
256 muter = insert(:user)
257 muted = insert(:user)
258 {:ok, _} = User.mute(muter, muted)
259 muter = Repo.get(User, muter.id)
260 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
262 notification = Notification.create_notification(activity, muter)
264 assert notification.id
265 assert notification.seen
268 test "notification created if user is muted without notifications" do
269 muter = insert(:user)
270 muted = insert(:user)
272 {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
274 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
276 assert Notification.create_notification(activity, muter)
279 test "it creates a notification for an activity from a muted thread" do
280 muter = insert(:user)
281 other_user = insert(:user)
282 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
283 CommonAPI.add_mute(muter, activity)
286 CommonAPI.post(other_user, %{
287 status: "Hi @#{muter.nickname}",
288 in_reply_to_status_id: activity.id
291 notification = Notification.create_notification(activity, muter)
293 assert notification.id
294 assert notification.seen
297 test "it disables notifications from strangers" do
298 follower = insert(:user)
302 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
305 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
306 refute Notification.create_notification(activity, followed)
309 test "it doesn't create a notification for user if he is the activity author" do
310 activity = insert(:note_activity)
311 author = User.get_cached_by_ap_id(activity.data["actor"])
313 refute Notification.create_notification(activity, author)
316 test "it doesn't create duplicate notifications for follow+subscribed users" do
318 subscriber = insert(:user)
320 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
321 User.subscribe(subscriber, user)
322 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
323 {:ok, [_notif]} = Notification.create_notifications(status)
326 test "it doesn't create subscription notifications if the recipient cannot see the status" do
328 subscriber = insert(:user)
330 User.subscribe(subscriber, user)
332 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
334 assert {:ok, []} == Notification.create_notifications(status)
337 test "it disables notifications from people who are invisible" do
338 author = insert(:user, invisible: true)
341 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
342 refute Notification.create_notification(status, user)
345 test "it doesn't create notifications if content matches with an irreversible filter" do
347 subscriber = insert(:user)
349 User.subscribe(subscriber, user)
350 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
352 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
354 assert {:ok, []} == Notification.create_notifications(status)
357 test "it creates notifications if content matches with a not irreversible filter" do
359 subscriber = insert(:user)
361 User.subscribe(subscriber, user)
362 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
364 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
365 {:ok, [notification]} = Notification.create_notifications(status)
368 refute notification.seen
371 test "it creates notifications when someone likes user's status with a filtered word" do
373 other_user = insert(:user)
374 insert(:filter, user: user, phrase: "tesla", hide: true)
376 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
377 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
379 {:ok, [notification]} = Notification.create_notifications(activity_two)
382 refute notification.seen
386 describe "follow / follow_request notifications" do
387 test "it creates `follow` notification for approved Follow activity" do
389 followed_user = insert(:user, is_locked: false)
391 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
392 assert FollowingRelationship.following?(user, followed_user)
393 assert [notification] = Notification.for_user(followed_user)
395 assert %{type: "follow"} =
396 NotificationView.render("show.json", %{
397 notification: notification,
402 test "it creates `follow_request` notification for pending Follow activity" do
404 followed_user = insert(:user, is_locked: true)
406 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
407 refute FollowingRelationship.following?(user, followed_user)
408 assert [notification] = Notification.for_user(followed_user)
410 render_opts = %{notification: notification, for: followed_user}
411 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
413 # After request is accepted, the same notification is rendered with type "follow":
414 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
417 Repo.get(Notification, notification.id)
418 |> Repo.preload(:activity)
420 assert %{type: "follow"} =
421 NotificationView.render("show.json", notification: notification, for: followed_user)
424 test "it doesn't create a notification for follow-unfollow-follow chains" do
426 followed_user = insert(:user, is_locked: false)
428 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
429 assert FollowingRelationship.following?(user, followed_user)
430 assert [notification] = Notification.for_user(followed_user)
432 CommonAPI.unfollow(user, followed_user)
433 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
435 notification_id = notification.id
436 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
439 test "dismisses the notification on follow request rejection" do
440 user = insert(:user, is_locked: true)
441 follower = insert(:user)
442 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
443 assert [_notification] = Notification.for_user(user)
444 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
445 assert [] = Notification.for_user(user)
449 describe "get notification" do
450 test "it gets a notification that belongs to the user" do
452 other_user = insert(:user)
454 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
456 {:ok, [notification]} = Notification.create_notifications(activity)
457 {:ok, notification} = Notification.get(other_user, notification.id)
459 assert notification.user_id == other_user.id
462 test "it returns error if the notification doesn't belong to the user" do
464 other_user = insert(:user)
466 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
468 {:ok, [notification]} = Notification.create_notifications(activity)
469 {:error, _notification} = Notification.get(user, notification.id)
473 describe "dismiss notification" do
474 test "it dismisses a notification that belongs to the user" do
476 other_user = insert(:user)
478 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
480 {:ok, [notification]} = Notification.create_notifications(activity)
481 {:ok, notification} = Notification.dismiss(other_user, notification.id)
483 assert notification.user_id == other_user.id
486 test "it returns error if the notification doesn't belong to the user" do
488 other_user = insert(:user)
490 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
492 {:ok, [notification]} = Notification.create_notifications(activity)
493 {:error, _notification} = Notification.dismiss(user, notification.id)
497 describe "clear notification" do
498 test "it clears all notifications belonging to the user" do
500 other_user = insert(:user)
501 third_user = insert(:user)
504 CommonAPI.post(user, %{
505 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
508 {:ok, _notifs} = Notification.create_notifications(activity)
511 CommonAPI.post(user, %{
512 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
515 {:ok, _notifs} = Notification.create_notifications(activity)
516 Notification.clear(other_user)
518 assert Notification.for_user(other_user) == []
519 assert Notification.for_user(third_user) != []
523 describe "destroy_multiple_from_types/2" do
524 test "clears all notifications of a certain type for a given user" do
525 report_activity = insert(:report_activity)
526 user1 = insert(:user, is_moderator: true, is_admin: true)
527 user2 = insert(:user, is_moderator: true, is_admin: true)
528 {:ok, _} = Notification.create_notifications(report_activity)
531 CommonAPI.post(user2, %{
532 status: "hey @#{user1.nickname} !"
535 Notification.destroy_multiple_from_types(user1, ["pleroma:report"])
537 assert [%Pleroma.Notification{type: "mention"}] = Notification.for_user(user1)
538 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user2)
542 describe "set_read_up_to()" do
543 test "it sets all notifications as read up to a specified notification ID" do
545 other_user = insert(:user)
548 CommonAPI.post(user, %{
549 status: "hey @#{other_user.nickname}!"
553 CommonAPI.post(user, %{
554 status: "hey again @#{other_user.nickname}!"
557 [n2, n1] = Notification.for_user(other_user)
562 CommonAPI.post(user, %{
563 status: "hey yet again @#{other_user.nickname}!"
566 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
568 assert read_notification.activity.object
570 [n3, n2, n1] = Notification.for_user(other_user)
572 assert n1.seen == true
573 assert n2.seen == true
574 assert n3.seen == false
576 assert %Pleroma.Marker{} =
580 user_id: other_user.id,
581 timeline: "notifications"
584 assert m.last_read_id == to_string(n2.id)
588 describe "for_user_since/2" do
589 defp days_ago(days) do
591 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
592 -days * 60 * 60 * 24,
597 test "Returns recent notifications" do
598 user1 = insert(:user)
599 user2 = insert(:user)
601 Enum.each(0..10, fn i ->
603 CommonAPI.post(user1, %{
604 status: "hey ##{i} @#{user2.nickname}!"
608 {old, new} = Enum.split(Notification.for_user(user2), 5)
610 Enum.each(old, fn notification ->
612 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
613 |> Pleroma.Repo.update!()
616 recent_notifications_ids =
618 |> Notification.for_user_since(
619 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
623 Enum.each(old, fn %{id: id} ->
624 refute id in recent_notifications_ids
627 Enum.each(new, fn %{id: id} ->
628 assert id in recent_notifications_ids
633 describe "notification target determination / get_notified_from_activity/2" do
634 test "it sends notifications to addressed users in new messages" do
636 other_user = insert(:user)
639 CommonAPI.post(user, %{
640 status: "hey @#{other_user.nickname}!"
643 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
645 assert other_user in enabled_receivers
648 test "it sends notifications to mentioned users in new messages" do
650 other_user = insert(:user)
653 "@context" => "https://www.w3.org/ns/activitystreams",
655 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
656 "actor" => user.ap_id,
659 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
660 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
661 "content" => "message with a Mention tag, but no explicit tagging",
665 "href" => other_user.ap_id,
666 "name" => other_user.nickname
669 "attributedTo" => user.ap_id
673 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
675 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
677 assert other_user in enabled_receivers
680 test "it does not send notifications to users who are only cc in new messages" do
682 other_user = insert(:user)
685 "@context" => "https://www.w3.org/ns/activitystreams",
687 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
688 "cc" => [other_user.ap_id],
689 "actor" => user.ap_id,
692 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
693 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
694 "cc" => [other_user.ap_id],
695 "content" => "hi everyone",
696 "attributedTo" => user.ap_id
700 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
702 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
704 assert other_user not in enabled_receivers
707 test "it does not send notification to mentioned users in likes" do
709 other_user = insert(:user)
710 third_user = insert(:user)
712 {:ok, activity_one} =
713 CommonAPI.post(user, %{
714 status: "hey @#{other_user.nickname}!"
717 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
719 {enabled_receivers, _disabled_receivers} =
720 Notification.get_notified_from_activity(activity_two)
722 assert other_user not in enabled_receivers
725 test "it only notifies the post's author in likes" do
727 other_user = insert(:user)
728 third_user = insert(:user)
730 {:ok, activity_one} =
731 CommonAPI.post(user, %{
732 status: "hey @#{other_user.nickname}!"
735 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
739 |> Map.put("to", [other_user.ap_id | like_data["to"]])
740 |> ActivityPub.persist(local: true)
742 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
744 assert other_user not in enabled_receivers
747 test "it does not send notification to mentioned users in announces" do
749 other_user = insert(:user)
750 third_user = insert(:user)
752 {:ok, activity_one} =
753 CommonAPI.post(user, %{
754 status: "hey @#{other_user.nickname}!"
757 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
759 {enabled_receivers, _disabled_receivers} =
760 Notification.get_notified_from_activity(activity_two)
762 assert other_user not in enabled_receivers
765 test "it returns blocking recipient in disabled recipients list" do
767 other_user = insert(:user)
768 {:ok, _user_relationship} = User.block(other_user, user)
770 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
772 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
774 assert [] == enabled_receivers
775 assert [other_user] == disabled_receivers
778 test "it returns notification-muting recipient in disabled recipients list" do
780 other_user = insert(:user)
781 {:ok, _user_relationships} = User.mute(other_user, user)
783 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
785 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
787 assert [] == enabled_receivers
788 assert [other_user] == disabled_receivers
791 test "it returns thread-muting recipient in disabled recipients list" do
793 other_user = insert(:user)
795 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
797 {:ok, _} = CommonAPI.add_mute(other_user, activity)
799 {:ok, same_context_activity} =
800 CommonAPI.post(user, %{
801 status: "hey-hey-hey @#{other_user.nickname}!",
802 in_reply_to_status_id: activity.id
805 {enabled_receivers, disabled_receivers} =
806 Notification.get_notified_from_activity(same_context_activity)
808 assert [other_user] == disabled_receivers
809 refute other_user in enabled_receivers
812 test "it returns non-following domain-blocking recipient in disabled recipients list" do
813 blocked_domain = "blocked.domain"
814 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
815 other_user = insert(:user)
817 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
819 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
821 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
823 assert [] == enabled_receivers
824 assert [other_user] == disabled_receivers
827 test "it returns following domain-blocking recipient in enabled recipients list" do
828 blocked_domain = "blocked.domain"
829 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
830 other_user = insert(:user)
832 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
833 {:ok, other_user, user} = User.follow(other_user, user)
835 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
837 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
839 assert [other_user] == enabled_receivers
840 assert [] == disabled_receivers
844 describe "notification lifecycle" do
845 test "liking an activity results in 1 notification, then 0 if the activity is deleted" 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.favorite(other_user, activity.id)
855 assert length(Notification.for_user(user)) == 1
857 {:ok, _} = CommonAPI.delete(activity.id, user)
859 assert Enum.empty?(Notification.for_user(user))
862 test "liking an activity results in 1 notification, then 0 if the activity is unliked" 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, _} = CommonAPI.favorite(other_user, activity.id)
872 assert length(Notification.for_user(user)) == 1
874 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
876 assert Enum.empty?(Notification.for_user(user))
879 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" 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, _} = CommonAPI.repeat(activity.id, other_user)
889 assert length(Notification.for_user(user)) == 1
891 {:ok, _} = CommonAPI.delete(activity.id, user)
893 assert Enum.empty?(Notification.for_user(user))
896 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
898 other_user = insert(:user)
900 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
902 assert Enum.empty?(Notification.for_user(user))
904 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
906 assert length(Notification.for_user(user)) == 1
908 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
910 assert Enum.empty?(Notification.for_user(user))
913 test "liking an activity which is already deleted does not generate a notification" do
915 other_user = insert(:user)
917 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
919 assert Enum.empty?(Notification.for_user(user))
921 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
923 assert Enum.empty?(Notification.for_user(user))
925 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
927 assert Enum.empty?(Notification.for_user(user))
930 test "repeating an activity which is already deleted does not generate a notification" do
932 other_user = insert(:user)
934 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
936 assert Enum.empty?(Notification.for_user(user))
938 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
940 assert Enum.empty?(Notification.for_user(user))
942 {:error, _} = CommonAPI.repeat(activity.id, other_user)
944 assert Enum.empty?(Notification.for_user(user))
947 test "replying to a deleted post without tagging does not generate a notification" do
949 other_user = insert(:user)
951 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
952 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
954 {:ok, _reply_activity} =
955 CommonAPI.post(other_user, %{
956 status: "test reply",
957 in_reply_to_status_id: activity.id
960 assert Enum.empty?(Notification.for_user(user))
963 test "notifications are deleted if a local user is deleted" do
965 other_user = insert(:user)
968 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
970 refute Enum.empty?(Notification.for_user(other_user))
972 {:ok, job} = User.delete(user)
973 ObanHelpers.perform(job)
975 assert Enum.empty?(Notification.for_user(other_user))
978 test "notifications are deleted if a remote user is deleted" do
979 remote_user = insert(:user)
980 local_user = insert(:user)
983 "@context" => "https://www.w3.org/ns/activitystreams",
985 "actor" => remote_user.ap_id,
986 "id" => remote_user.ap_id <> "/activities/test",
987 "to" => [local_user.ap_id],
991 "id" => remote_user.ap_id <> "/objects/test",
992 "content" => "Hello!",
996 "href" => local_user.ap_id,
997 "name" => "@#{local_user.nickname}"
1000 "to" => [local_user.ap_id],
1002 "attributedTo" => remote_user.ap_id
1006 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
1008 refute Enum.empty?(Notification.for_user(local_user))
1010 delete_user_message = %{
1011 "@context" => "https://www.w3.org/ns/activitystreams",
1012 "id" => remote_user.ap_id <> "/activities/delete",
1013 "actor" => remote_user.ap_id,
1015 "object" => remote_user.ap_id
1018 remote_user_url = remote_user.ap_id
1021 %{method: :get, url: ^remote_user_url} ->
1022 %Tesla.Env{status: 404, body: ""}
1025 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
1026 ObanHelpers.perform_all()
1028 assert Enum.empty?(Notification.for_user(local_user))
1031 test "move activity generates a notification" do
1032 %{ap_id: old_ap_id} = old_user = insert(:user)
1033 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1034 follower = insert(:user)
1035 other_follower = insert(:user, %{allow_following_move: false})
1037 User.follow(follower, old_user)
1038 User.follow(other_follower, old_user)
1040 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1041 ObanHelpers.perform_all()
1046 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1049 ] = Notification.for_user(follower)
1054 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1057 ] = Notification.for_user(other_follower)
1061 describe "for_user" do
1063 user = insert(:user)
1065 {:ok, %{user: user}}
1068 test "it returns notifications for muted user without notifications", %{user: user} do
1069 muted = insert(:user)
1070 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1072 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1074 [notification] = Notification.for_user(user)
1076 assert notification.activity.object
1077 assert notification.seen
1080 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1081 muted = insert(:user)
1082 {:ok, _user_relationships} = User.mute(user, muted)
1084 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1086 assert Notification.for_user(user) == []
1089 test "it doesn't return notifications for blocked user", %{user: user} do
1090 blocked = insert(:user)
1091 {:ok, _user_relationship} = User.block(user, blocked)
1093 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1095 assert Notification.for_user(user) == []
1098 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
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 Notification.for_user(user) == []
1107 test "it returns notifications for domain-blocked but followed user" do
1108 user = insert(:user)
1109 blocked = insert(:user, ap_id: "http://some-domain.com")
1111 {:ok, user} = User.block_domain(user, "some-domain.com")
1112 {:ok, _, _} = User.follow(user, blocked)
1114 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1116 assert length(Notification.for_user(user)) == 1
1119 test "it doesn't return notifications for muted thread", %{user: user} do
1120 another_user = insert(:user)
1122 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1124 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1125 assert Notification.for_user(user) == []
1128 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1129 muted = insert(:user)
1130 {:ok, _user_relationships} = User.mute(user, muted)
1132 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1134 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1137 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1140 blocked = insert(:user)
1141 {:ok, _user_relationship} = User.block(user, blocked)
1143 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1145 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1148 test "when with_muted is set, " <>
1149 "it doesn't return notifications from a domain-blocked non-followed user",
1151 blocked = insert(:user, ap_id: "http://some-domain.com")
1152 {:ok, user} = User.block_domain(user, "some-domain.com")
1154 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1156 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1159 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1160 another_user = insert(:user)
1162 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1164 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1165 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1168 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1169 insert(:filter, user: user, phrase: "cofe", hide: true)
1170 another_user = insert(:user)
1172 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1174 assert Enum.empty?(Notification.for_user(user))
1177 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1178 insert(:filter, user: user, phrase: "test", hide: false)
1179 another_user = insert(:user)
1181 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1183 assert length(Notification.for_user(user)) == 1
1186 test "it returns notifications about favorites with filtered word", %{user: user} do
1187 insert(:filter, user: user, phrase: "cofe", hide: true)
1188 another_user = insert(:user)
1190 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1191 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1193 assert length(Notification.for_user(user)) == 1