Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85826904
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
79 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs
index 2ad950e84..a2be2ae49 100644
--- a/test/pleroma/notification_test.exs
+++ b/test/pleroma/notification_test.exs
@@ -1,1156 +1,1156 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.NotificationTest do
use Pleroma.DataCase, async: false
import Pleroma.Factory
alias Pleroma.FollowingRelationship
alias Pleroma.Notification
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.Streamer
setup do
Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
:ok
end
describe "create_notifications" do
test "never returns nil" do
user = insert(:user)
other_user = insert(:user, %{invisible: true})
{:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
{:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
refute {:ok, [nil]} == Notification.create_notifications(activity)
end
test "creates a report notification only for privileged users" do
reporting_user = insert(:user)
reported_user = insert(:user)
moderator_user = insert(:user, is_moderator: true)
clear_config([:instance, :moderator_privileges], [])
{:ok, activity1} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
{:ok, []} = Notification.create_notifications(activity1)
clear_config([:instance, :moderator_privileges], [:reports_manage_reports])
{:ok, activity2} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
{:ok, [notification]} = Notification.create_notifications(activity2)
assert notification.user_id == moderator_user.id
assert notification.type == "pleroma:report"
end
test "suppresses notifications for own reports" do
clear_config([:instance, :admin_privileges], [:reports_manage_reports])
reporting_admin = insert(:user, is_admin: true)
reported_user = insert(:user)
other_admin = insert(:user, is_admin: true)
{:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id})
{:ok, [notification]} = Notification.create_notifications(activity)
refute notification.user_id == reporting_admin.id
assert notification.user_id == other_admin.id
assert notification.type == "pleroma:report"
end
test "creates a notification for an emoji reaction" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
{:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
{:ok, [notification]} = Notification.create_notifications(activity)
assert notification.user_id == user.id
assert notification.type == "pleroma:emoji_reaction"
end
test "notifies someone when they are directly addressed" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
})
{:ok, [notification, other_notification]} = Notification.create_notifications(activity)
notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
assert notified_ids == [other_user.id, third_user.id]
assert notification.activity_id == activity.id
assert notification.type == "mention"
assert other_notification.activity_id == activity.id
assert [%Pleroma.Marker{unread_count: 2}] =
Pleroma.Marker.get_markers(other_user, ["notifications"])
end
test "it creates a notification for subscribed users" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
{:ok, [notification]} = Notification.create_notifications(status)
assert notification.user_id == subscriber.id
assert notification.type == "status"
end
test "does not create a notification for subscribed users if status is a reply" do
user = insert(:user)
other_user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, other_user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
{:ok, _reply_activity} =
CommonAPI.post(other_user, %{
status: "test reply",
in_reply_to_status_id: activity.id
})
user_notifications = Notification.for_user(user)
assert length(user_notifications) == 1
subscriber_notifications = Notification.for_user(subscriber)
assert Enum.empty?(subscriber_notifications)
end
test "does not create subscriber notification if mentioned" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{status: "mentioning @#{subscriber.nickname}"})
{:ok, [notification] = notifications} = Notification.create_notifications(status)
assert length(notifications) == 1
assert notification.user_id == subscriber.id
assert notification.type == "mention"
end
test "it sends edited notifications to those who repeated a status" do
user = insert(:user)
repeated_user = insert(:user)
other_user = insert(:user)
{:ok, activity_one} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, _activity_two} = CommonAPI.repeat(activity_one.id, repeated_user)
{:ok, _edit_activity} =
CommonAPI.update(activity_one, user, %{
status: "hey @#{other_user.nickname}! mew mew"
})
assert [%{type: "reblog"}] = Notification.for_user(user)
assert [%{type: "update"}] = Notification.for_user(repeated_user)
assert [%{type: "mention"}] = Notification.for_user(other_user)
end
end
test "create_poll_notifications/1" do
[user1, user2, user3, _, _] = insert_list(5, :user)
question = insert(:question, user: user1)
activity = insert(:question_activity, question: question)
{:ok, _, _} = CommonAPI.vote(question, user2, [0])
{:ok, _, _} = CommonAPI.vote(question, user3, [1])
{:ok, notifications} = Notification.create_poll_notifications(activity)
assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
end
describe "create_notification" do
test "it disables notifications from strangers" do
follower = insert(:user)
followed =
insert(:user,
notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
)
{:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
refute Notification.create_notification(activity, followed)
end
test "it disables notifications from non-followees" do
follower = insert(:user)
followed =
insert(:user,
notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
)
CommonAPI.follow(followed, follower)
{:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
refute Notification.create_notification(activity, followed)
end
test "it allows notifications from followees" do
poster = insert(:user)
receiver =
insert(:user,
notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
)
CommonAPI.follow(poster, receiver)
{:ok, activity} = CommonAPI.post(poster, %{status: "hey @#{receiver.nickname}"})
assert Notification.create_notification(activity, receiver)
end
test "it doesn't create a notification for user if he is the activity author" do
activity = insert(:note_activity)
author = User.get_cached_by_ap_id(activity.data["actor"])
refute Notification.create_notification(activity, author)
end
test "it doesn't create duplicate notifications for follow+subscribed users" do
user = insert(:user)
subscriber = insert(:user)
{:ok, _, _, _} = CommonAPI.follow(user, subscriber)
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
{:ok, [_notif]} = Notification.create_notifications(status)
end
test "it doesn't create subscription notifications if the recipient cannot see the status" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
{:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
assert {:ok, []} == Notification.create_notifications(status)
end
test "it disables notifications from people who are invisible" do
author = insert(:user, invisible: true)
user = insert(:user)
{:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
refute Notification.create_notification(status, user)
end
test "it doesn't create notifications if content matches with an irreversible filter" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
insert(:filter, user: subscriber, phrase: "cofe", hide: true)
{:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
assert {:ok, []} == Notification.create_notifications(status)
end
test "it creates notifications if content matches with a not irreversible filter" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
insert(:filter, user: subscriber, phrase: "cofe", hide: false)
{:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
{:ok, [notification]} = Notification.create_notifications(status)
assert notification
refute notification.seen
end
test "it creates notifications when someone likes user's status with a filtered word" do
user = insert(:user)
other_user = insert(:user)
insert(:filter, user: user, phrase: "tesla", hide: true)
{:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
{:ok, activity_two} = CommonAPI.favorite(activity_one.id, other_user)
{:ok, [notification]} = Notification.create_notifications(activity_two)
assert notification
refute notification.seen
end
end
describe "follow / follow_request notifications" do
test "it creates `follow` notification for approved Follow activity" do
user = insert(:user)
followed_user = insert(:user, is_locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(followed_user, user)
assert FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
assert %{type: "follow"} =
NotificationView.render("show.json", %{
notification: notification,
for: followed_user
})
end
test "it creates `follow_request` notification for pending Follow activity" do
user = insert(:user)
followed_user = insert(:user, is_locked: true)
{:ok, _, _, _activity} = CommonAPI.follow(followed_user, user)
refute FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
render_opts = %{notification: notification, for: followed_user}
assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
# After request is accepted, the same notification is rendered with type "follow":
assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
notification =
Repo.get(Notification, notification.id)
|> Repo.preload(:activity)
assert %{type: "follow"} =
NotificationView.render("show.json",
notification: notification,
for: followed_user
)
end
test "it doesn't create a notification for follow-unfollow-follow chains" do
user = insert(:user)
followed_user = insert(:user, is_locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(followed_user, user)
assert FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
CommonAPI.unfollow(followed_user, user)
{:ok, _, _, _activity_dupe} = CommonAPI.follow(followed_user, user)
notification_id = notification.id
assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
end
test "dismisses the notification on follow request rejection" do
user = insert(:user, is_locked: true)
follower = insert(:user)
{:ok, _, _, _follow_activity} = CommonAPI.follow(user, follower)
assert [_notification] = Notification.for_user(user)
{:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
assert [] = Notification.for_user(user)
end
end
describe "get notification" do
test "it gets a notification that belongs to the user" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:ok, notification} = Notification.get(other_user, notification.id)
assert notification.user_id == other_user.id
end
test "it returns error if the notification doesn't belong to the user" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:error, _notification} = Notification.get(user, notification.id)
end
end
describe "dismiss notification" do
test "it dismisses a notification that belongs to the user" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:ok, notification} = Notification.dismiss(other_user, notification.id)
assert notification.user_id == other_user.id
end
test "it returns error if the notification doesn't belong to the user" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
{:error, _notification} = Notification.dismiss(user, notification.id)
end
end
describe "clear notification" do
test "it clears all notifications belonging to the user" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
})
{:ok, _notifs} = Notification.create_notifications(activity)
{:ok, activity} =
CommonAPI.post(user, %{
status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
})
{:ok, _notifs} = Notification.create_notifications(activity)
Notification.clear(other_user)
assert Notification.for_user(other_user) == []
assert Notification.for_user(third_user) != []
end
end
describe "set_read_up_to()" do
test "it sets all notifications as read up to a specified notification ID" do
[user, other_user] = insert_pair(:user)
{:ok, _activity} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, _activity} =
CommonAPI.post(user, %{
status: "hey again @#{other_user.nickname}!"
})
[n2, n1] = Notification.for_user(other_user)
assert n2.id > n1.id
{:ok, _activity} =
CommonAPI.post(user, %{
status: "hey yet again @#{other_user.nickname}!"
})
Notification.set_read_up_to(other_user, n2.id)
[n3, n2, n1] = Notification.for_user(other_user)
assert n1.seen == true
assert n2.seen == true
assert n3.seen == false
assert %Pleroma.Marker{} =
m =
Pleroma.Repo.get_by(
Pleroma.Marker,
user_id: other_user.id,
timeline: "notifications"
)
assert m.last_read_id == to_string(n2.id)
end
@tag needs_streamer: true
- test "it send updated marker to the 'user' and the 'user:notification' stream" do
+ test "it sends updated marker to the 'user' and the 'user:notification' stream" do
%{user: user, token: oauth_token} = oauth_access(["read"])
other_user = insert(:user)
{:ok, _activity} =
CommonAPI.post(other_user, %{
status: "hi @#{user.nickname}!"
})
[%{id: notification_id}] = Notification.for_user(user)
notification_id = to_string(notification_id)
task =
Task.async(fn ->
{:ok, _topic} =
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
assert_receive {:text, event}, 4_000
assert %{"event" => "marker", "payload" => payload} = Jason.decode!(event)
assert %{"notifications" => %{"last_read_id" => ^notification_id}} =
Jason.decode!(payload)
end)
Notification.set_read_up_to(user, notification_id)
Task.await(task)
end
end
describe "for_user_since/2" do
defp days_ago(days) do
NaiveDateTime.add(
NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
-days * 60 * 60 * 24,
:second
)
end
test "Returns recent notifications" do
user1 = insert(:user)
user2 = insert(:user)
Enum.each(0..10, fn i ->
{:ok, _activity} =
CommonAPI.post(user1, %{
status: "hey ##{i} @#{user2.nickname}!"
})
end)
{old, new} = Enum.split(Notification.for_user(user2), 5)
Enum.each(old, fn notification ->
notification
|> cast(%{updated_at: days_ago(10)}, [:updated_at])
|> Pleroma.Repo.update!()
end)
recent_notifications_ids =
user2
|> Notification.for_user_since(
NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
)
|> Enum.map(& &1.id)
Enum.each(old, fn %{id: id} ->
refute id in recent_notifications_ids
end)
Enum.each(new, fn %{id: id} ->
assert id in recent_notifications_ids
end)
end
end
describe "notification target determination / get_notified_from_activity/2" do
test "it sends notifications to addressed users in new messages" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
enabled_receivers = Notification.get_notified_from_activity(activity)
assert other_user in enabled_receivers
end
test "it sends notifications to mentioned users in new messages" do
user = insert(:user)
other_user = insert(:user)
create_activity = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => user.ap_id,
"object" => %{
"type" => "Note",
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"content" => "message with a Mention tag, but no explicit tagging",
"tag" => [
%{
"type" => "Mention",
"href" => other_user.ap_id,
"name" => other_user.nickname
}
],
"attributedTo" => user.ap_id
}
}
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
enabled_receivers = Notification.get_notified_from_activity(activity)
assert other_user in enabled_receivers
end
test "it does not send notifications to users who are only cc in new messages" do
user = insert(:user)
other_user = insert(:user)
create_activity = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [other_user.ap_id],
"actor" => user.ap_id,
"object" => %{
"type" => "Note",
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"cc" => [other_user.ap_id],
"content" => "hi everyone",
"attributedTo" => user.ap_id
}
}
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
enabled_receivers = Notification.get_notified_from_activity(activity)
assert other_user not in enabled_receivers
end
test "it does not send notification to mentioned users in likes" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity_one} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, activity_two} = CommonAPI.favorite(activity_one.id, third_user)
enabled_receivers = Notification.get_notified_from_activity(activity_two)
assert other_user not in enabled_receivers
end
test "it only notifies the post's author in likes" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity_one} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, like_data, _} = Builder.like(third_user, activity_one.object)
{:ok, like, _} =
like_data
|> Map.put("to", [other_user.ap_id | like_data["to"]])
|> ActivityPub.persist(local: true)
enabled_receivers = Notification.get_notified_from_activity(like)
assert other_user not in enabled_receivers
end
test "it does not send notification to mentioned users in announces" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity_one} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
enabled_receivers = Notification.get_notified_from_activity(activity_two)
assert other_user not in enabled_receivers
end
test "it does not return blocking recipient in recipients list" do
user = insert(:user)
other_user = insert(:user)
{:ok, _user_relationship} = User.block(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
enabled_receivers = Notification.get_notified_from_activity(activity)
assert [] == enabled_receivers
end
test "it does not return notification-muting recipient in recipients list" do
user = insert(:user)
other_user = insert(:user)
{:ok, _user_relationships} = User.mute(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
enabled_receivers = Notification.get_notified_from_activity(activity)
assert [] == enabled_receivers
end
test "it does not return thread-muting recipient in recipients list" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
{:ok, _} = CommonAPI.add_mute(activity, other_user)
{:ok, same_context_activity} =
CommonAPI.post(user, %{
status: "hey-hey-hey @#{other_user.nickname}!",
in_reply_to_status_id: activity.id
})
enabled_receivers = Notification.get_notified_from_activity(same_context_activity)
refute other_user in enabled_receivers
end
test "it does not return non-following domain-blocking recipient in recipients list" do
blocked_domain = "blocked.domain"
user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
other_user = insert(:user)
{:ok, other_user} = User.block_domain(other_user, blocked_domain)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
enabled_receivers = Notification.get_notified_from_activity(activity)
assert [] == enabled_receivers
end
test "it returns following domain-blocking recipient in enabled recipients list" do
blocked_domain = "blocked.domain"
user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
other_user = insert(:user)
{:ok, other_user} = User.block_domain(other_user, blocked_domain)
{:ok, other_user, user} = User.follow(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
enabled_receivers = Notification.get_notified_from_activity(activity)
assert [other_user] == enabled_receivers
end
test "it sends edited notifications to those who repeated a status" do
user = insert(:user)
repeated_user = insert(:user)
other_user = insert(:user)
{:ok, activity_one} =
CommonAPI.post(user, %{
status: "hey @#{other_user.nickname}!"
})
{:ok, _activity_two} = CommonAPI.repeat(activity_one.id, repeated_user)
{:ok, edit_activity} =
CommonAPI.update(activity_one, user, %{
status: "hey @#{other_user.nickname}! mew mew"
})
enabled_receivers = Notification.get_notified_from_activity(edit_activity)
assert repeated_user in enabled_receivers
refute other_user in enabled_receivers
end
end
describe "notification lifecycle" do
test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _} = CommonAPI.favorite(activity.id, other_user)
assert length(Notification.for_user(user)) == 1
{:ok, _} = CommonAPI.delete(activity.id, user)
assert Enum.empty?(Notification.for_user(user))
end
test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _} = CommonAPI.favorite(activity.id, other_user)
assert length(Notification.for_user(user)) == 1
{:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
assert Enum.empty?(Notification.for_user(user))
end
test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _} = CommonAPI.repeat(activity.id, other_user)
assert length(Notification.for_user(user)) == 1
{:ok, _} = CommonAPI.delete(activity.id, user)
assert Enum.empty?(Notification.for_user(user))
end
test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _} = CommonAPI.repeat(activity.id, other_user)
assert length(Notification.for_user(user)) == 1
{:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
assert Enum.empty?(Notification.for_user(user))
end
test "liking an activity which is already deleted does not generate a notification" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
assert Enum.empty?(Notification.for_user(user))
{:error, :not_found} = CommonAPI.favorite(activity.id, other_user)
assert Enum.empty?(Notification.for_user(user))
end
test "repeating an activity which is already deleted does not generate a notification" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test post"})
assert Enum.empty?(Notification.for_user(user))
{:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
assert Enum.empty?(Notification.for_user(user))
{:error, _} = CommonAPI.repeat(activity.id, other_user)
assert Enum.empty?(Notification.for_user(user))
end
test "notifications are deleted if a local user is deleted" do
user = insert(:user)
other_user = insert(:user)
{:ok, _activity} =
CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
refute Enum.empty?(Notification.for_user(other_user))
{:ok, job} = User.delete(user)
ObanHelpers.perform(job)
assert Enum.empty?(Notification.for_user(other_user))
end
test "notifications are deleted if a remote user is deleted" do
remote_user = insert(:user)
local_user = insert(:user)
dm_message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"actor" => remote_user.ap_id,
"id" => remote_user.ap_id <> "/activities/test",
"to" => [local_user.ap_id],
"cc" => [],
"object" => %{
"type" => "Note",
"id" => remote_user.ap_id <> "/objects/test",
"content" => "Hello!",
"tag" => [
%{
"type" => "Mention",
"href" => local_user.ap_id,
"name" => "@#{local_user.nickname}"
}
],
"to" => [local_user.ap_id],
"cc" => [],
"attributedTo" => remote_user.ap_id
}
}
{:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
refute Enum.empty?(Notification.for_user(local_user))
delete_user_message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"id" => remote_user.ap_id <> "/activities/delete",
"actor" => remote_user.ap_id,
"type" => "Delete",
"object" => remote_user.ap_id
}
remote_user_url = remote_user.ap_id
Tesla.Mock.mock(fn
%{method: :get, url: ^remote_user_url} ->
%Tesla.Env{status: 404, body: ""}
end)
{:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
ObanHelpers.perform_all()
assert Enum.empty?(Notification.for_user(local_user))
end
test "move activity generates a notification" do
%{ap_id: old_ap_id} = old_user = insert(:user)
%{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
follower = insert(:user)
other_follower = insert(:user, %{allow_following_move: false})
User.follow(follower, old_user)
User.follow(other_follower, old_user)
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
ObanHelpers.perform_all()
assert [
%{
activity: %{
data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
}
}
] = Notification.for_user(follower)
assert [
%{
activity: %{
data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
}
}
] = Notification.for_user(other_follower)
end
end
describe "for_user" do
setup do
user = insert(:user)
{:ok, %{user: user}}
end
test "it returns notifications for muted user without notifications", %{user: user} do
muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
[notification] = Notification.for_user(user)
assert notification.activity.object
assert notification.seen
end
test "it doesn't return notifications for muted user with notifications", %{user: user} do
muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted)
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
assert Notification.for_user(user) == []
end
test "it doesn't return notifications for blocked user", %{user: user} do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Notification.for_user(user) == []
end
test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Notification.for_user(user) == []
end
test "it returns notifications for domain-blocked but followed user" do
user = insert(:user)
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
{:ok, _, _} = User.follow(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert length(Notification.for_user(user)) == 1
end
test "it doesn't return notifications for muted thread", %{user: user} do
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
{:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
assert Notification.for_user(user) == []
end
test "it doesn't return notifications from a muted user when with_muted is set", %{user: user} do
muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted)
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
end
test "it doesn't return notifications from a blocked user when with_muted is set", %{
user: user
} do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
end
test "when with_muted is set, " <>
"it doesn't return notifications from a domain-blocked non-followed user",
%{user: user} do
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
end
test "it returns notifications from muted threads when with_muted is set", %{user: user} do
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
{:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
assert length(Notification.for_user(user, %{with_muted: true})) == 1
end
test "it doesn't return notifications about mentions with filtered word", %{user: user} do
insert(:filter, user: user, phrase: "cofe", hide: true)
another_user = insert(:user)
{:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
assert Enum.empty?(Notification.for_user(user))
end
test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
insert(:filter, user: user, phrase: "test", hide: false)
another_user = insert(:user)
{:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
assert length(Notification.for_user(user)) == 1
end
test "it returns notifications about favorites with filtered word", %{user: user} do
insert(:filter, user: user, phrase: "cofe", hide: true)
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
{:ok, _} = CommonAPI.favorite(activity.id, another_user)
assert length(Notification.for_user(user)) == 1
end
test "it returns notifications when related object is without content and filters are defined",
%{user: user} do
followed_user = insert(:user, is_locked: true)
insert(:filter, user: followed_user, phrase: "test", hide: true)
{:ok, _, _, _activity} = CommonAPI.follow(followed_user, user)
refute FollowingRelationship.following?(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
assert %{type: "follow_request"} =
NotificationView.render("show.json", %{
notification: notification,
for: followed_user
})
assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
assert [notification] = Notification.for_user(followed_user)
assert %{type: "follow"} =
NotificationView.render("show.json", %{
notification: notification,
for: followed_user
})
end
end
end
diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs
index 85978e824..096ca2d2a 100644
--- a/test/pleroma/web/streamer_test.exs
+++ b/test/pleroma/web/streamer_test.exs
@@ -1,1112 +1,1112 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.StreamerTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
alias Pleroma.Conversation.Participation
alias Pleroma.List
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Streamer
alias Pleroma.Web.StreamerView
@moduletag needs_streamer: true, capture_log: true
setup do: clear_config([:instance, :skip_thread_containment])
describe "get_topic/_ (unauthenticated)" do
test "allows no stream" do
assert {:ok, nil} = Streamer.get_topic(nil, nil, nil)
end
test "allows public" do
assert {:ok, "public"} = Streamer.get_topic("public", nil, nil)
assert {:ok, "public:local"} = Streamer.get_topic("public:local", nil, nil)
assert {:ok, "public:media"} = Streamer.get_topic("public:media", nil, nil)
assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil, nil)
end
test "rejects local public streams if restricted_unauthenticated is on" do
clear_config([:restrict_unauthenticated, :timelines, :local], true)
assert {:error, :unauthorized} = Streamer.get_topic("public:local", nil, nil)
assert {:error, :unauthorized} = Streamer.get_topic("public:local:media", nil, nil)
end
test "rejects remote public streams if restricted_unauthenticated is on" do
clear_config([:restrict_unauthenticated, :timelines, :federated], true)
assert {:error, :unauthorized} = Streamer.get_topic("public", nil, nil)
assert {:error, :unauthorized} = Streamer.get_topic("public:media", nil, nil)
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote:media", nil, nil, %{"instance" => "lain.com"})
end
test "allows instance streams" do
assert {:ok, "public:remote:lain.com"} =
Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
assert {:ok, "public:remote:media:lain.com"} =
Streamer.get_topic("public:remote:media", nil, nil, %{"instance" => "lain.com"})
end
test "allows hashtag streams" do
assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", nil, nil, %{"tag" => "cofe"})
end
test "disallows user streams" do
assert {:error, _} = Streamer.get_topic("user", nil, nil)
assert {:error, _} = Streamer.get_topic("user:notification", nil, nil)
assert {:error, _} = Streamer.get_topic("direct", nil, nil)
end
test "disallows list streams" do
assert {:error, _} = Streamer.get_topic("list", nil, nil, %{"list" => 42})
end
end
describe "get_topic/_ (authenticated)" do
setup do: oauth_access(["read"])
test "allows public streams (regardless of OAuth token scopes)", %{
user: user,
token: read_oauth_token
} do
with oauth_token <- [nil, read_oauth_token] do
assert {:ok, "public"} = Streamer.get_topic("public", user, oauth_token)
assert {:ok, "public:local"} = Streamer.get_topic("public:local", user, oauth_token)
assert {:ok, "public:media"} = Streamer.get_topic("public:media", user, oauth_token)
assert {:ok, "public:local:media"} =
Streamer.get_topic("public:local:media", user, oauth_token)
end
end
test "allows local public streams if restricted_unauthenticated is on", %{
user: user,
token: oauth_token
} do
clear_config([:restrict_unauthenticated, :timelines, :local], true)
%{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
%{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
assert {:ok, "public:local"} = Streamer.get_topic("public:local", user, oauth_token)
assert {:ok, "public:local:media"} =
Streamer.get_topic("public:local:media", user, oauth_token)
for token <- [read_notifications_token, badly_scoped_token] do
assert {:error, :unauthorized} = Streamer.get_topic("public:local", user, token)
assert {:error, :unauthorized} = Streamer.get_topic("public:local:media", user, token)
end
end
test "allows remote public streams if restricted_unauthenticated is on", %{
user: user,
token: oauth_token
} do
clear_config([:restrict_unauthenticated, :timelines, :federated], true)
%{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
%{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
assert {:ok, "public"} = Streamer.get_topic("public", user, oauth_token)
assert {:ok, "public:media"} = Streamer.get_topic("public:media", user, oauth_token)
assert {:ok, "public:remote:lain.com"} =
Streamer.get_topic("public:remote", user, oauth_token, %{"instance" => "lain.com"})
assert {:ok, "public:remote:media:lain.com"} =
Streamer.get_topic("public:remote:media", user, oauth_token, %{
"instance" => "lain.com"
})
for token <- [read_notifications_token, badly_scoped_token] do
assert {:error, :unauthorized} = Streamer.get_topic("public", user, token)
assert {:error, :unauthorized} = Streamer.get_topic("public:media", user, token)
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote", user, token, %{
"instance" => "lain.com"
})
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote:media", user, token, %{
"instance" => "lain.com"
})
end
end
test "allows user streams (with proper OAuth token scopes)", %{
user: user,
token: read_oauth_token
} do
%{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
%{token: read_statuses_token} = oauth_access(["read:statuses"], user: user)
%{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
expected_user_topic = "user:#{user.id}"
expected_notification_topic = "user:notification:#{user.id}"
expected_direct_topic = "direct:#{user.id}"
expected_pleroma_chat_topic = "user:pleroma_chat:#{user.id}"
for valid_user_token <- [read_oauth_token, read_statuses_token] do
assert {:ok, ^expected_user_topic} = Streamer.get_topic("user", user, valid_user_token)
assert {:ok, ^expected_direct_topic} =
Streamer.get_topic("direct", user, valid_user_token)
assert {:ok, ^expected_pleroma_chat_topic} =
Streamer.get_topic("user:pleroma_chat", user, valid_user_token)
end
for invalid_user_token <- [read_notifications_token, badly_scoped_token],
user_topic <- ["user", "direct", "user:pleroma_chat"] do
assert {:error, :unauthorized} = Streamer.get_topic(user_topic, user, invalid_user_token)
end
for valid_notification_token <- [read_oauth_token, read_notifications_token] do
assert {:ok, ^expected_notification_topic} =
Streamer.get_topic("user:notification", user, valid_notification_token)
end
for invalid_notification_token <- [read_statuses_token, badly_scoped_token] do
assert {:error, :unauthorized} =
Streamer.get_topic("user:notification", user, invalid_notification_token)
end
end
test "allows hashtag streams (regardless of OAuth token scopes)", %{
user: user,
token: read_oauth_token
} do
for oauth_token <- [nil, read_oauth_token] do
assert {:ok, "hashtag:cofe"} =
Streamer.get_topic("hashtag", user, oauth_token, %{"tag" => "cofe"})
end
end
test "disallows registering to another user's stream", %{user: user, token: read_oauth_token} do
another_user = insert(:user)
assert {:error, _} = Streamer.get_topic("user:#{another_user.id}", user, read_oauth_token)
assert {:error, _} =
Streamer.get_topic("user:notification:#{another_user.id}", user, read_oauth_token)
assert {:error, _} = Streamer.get_topic("direct:#{another_user.id}", user, read_oauth_token)
end
test "allows list stream that are owned by the user (with `read` or `read:lists` scopes)", %{
user: user,
token: read_oauth_token
} do
%{token: read_lists_token} = oauth_access(["read:lists"], user: user)
%{token: invalid_token} = oauth_access(["irrelevant:scope"], user: user)
{:ok, list} = List.create("Test", user)
assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, read_oauth_token)
for valid_token <- [read_oauth_token, read_lists_token] do
assert {:ok, _} = Streamer.get_topic("list", user, valid_token, %{"list" => list.id})
end
assert {:error, _} = Streamer.get_topic("list", user, invalid_token, %{"list" => list.id})
end
test "disallows list stream that are not owned by the user", %{user: user, token: oauth_token} do
another_user = insert(:user)
{:ok, list} = List.create("Test", another_user)
assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, oauth_token)
assert {:error, _} = Streamer.get_topic("list", user, oauth_token, %{"list" => list.id})
end
end
describe "user streams" do
setup do
%{user: user, token: token} = oauth_access(["read"])
notify = insert(:notification, user: user, activity: build(:note_activity))
{:ok, %{user: user, notify: notify, token: token}}
end
test "it streams the user's post in the 'user' stream", %{user: user, token: oauth_token} do
Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
assert_receive {:render_with_user, _, _, ^activity, _}
refute Streamer.filtered_by_user?(user, activity)
end
test "it streams boosts of the user in the 'user' stream", %{user: user, token: oauth_token} do
Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
{:ok, announce} = CommonAPI.repeat(activity.id, user)
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce, _}
refute Streamer.filtered_by_user?(user, announce)
end
test "it does not stream announces of the user's own posts in the 'user' stream", %{
user: user,
token: oauth_token
} do
Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, announce} = CommonAPI.repeat(activity.id, other_user)
assert Streamer.filtered_by_user?(user, announce)
end
test "it does stream notifications announces of the user's own posts in the 'user' stream", %{
user: user,
token: oauth_token
} do
Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, announce} = CommonAPI.repeat(activity.id, other_user)
notification =
Pleroma.Notification
|> Repo.get_by(%{user_id: user.id, activity_id: announce.id})
|> Repo.preload(:activity)
refute Streamer.filtered_by_user?(user, notification)
end
test "it streams boosts of mastodon user in the 'user' stream", %{
user: user,
token: oauth_token
} do
Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Jason.decode!()
|> Map.put("object", activity.data["object"])
|> Map.put("actor", user.ap_id)
{:ok, %Pleroma.Activity{data: _data, local: false} = announce} =
Pleroma.Web.ActivityPub.Transmogrifier.handle_incoming(data)
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce, _}
refute Streamer.filtered_by_user?(user, announce)
end
test "it sends notify to in the 'user' stream", %{
user: user,
token: oauth_token,
notify: notify
} do
Streamer.get_topic_and_add_socket("user", user, oauth_token)
Streamer.stream("user", notify)
assert_receive {:render_with_user, _, _, ^notify, _}
refute Streamer.filtered_by_user?(user, notify)
end
test "it sends notify to in the 'user:notification' stream", %{
user: user,
token: oauth_token,
notify: notify
} do
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
Streamer.stream("user:notification", notify)
assert_receive {:render_with_user, _, _, ^notify, _}
refute Streamer.filtered_by_user?(user, notify)
end
test "it sends chat messages to the 'user:pleroma_chat' stream", %{
user: user,
token: oauth_token
} do
other_user = insert(:user)
{:ok, create_activity} =
CommonAPI.post_chat_message(other_user, user, "hey cirno", idempotency_key: "123")
object = Object.normalize(create_activity, fetch: false)
chat = Chat.get(user.id, other_user.ap_id)
cm_ref = MessageReference.for_chat_and_object(chat, object)
cm_ref = %{cm_ref | chat: chat, object: object}
Streamer.get_topic_and_add_socket("user:pleroma_chat", user, oauth_token)
Streamer.stream("user:pleroma_chat", {user, cm_ref})
text =
StreamerView.render(
"chat_update.json",
%{chat_message_reference: cm_ref},
"user:pleroma_chat:#{user.id}"
)
assert text =~ "hey cirno"
assert_receive {:text, ^text}
end
test "it sends chat messages to the 'user' stream", %{user: user, token: oauth_token} do
other_user = insert(:user)
{:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno")
object = Object.normalize(create_activity, fetch: false)
chat = Chat.get(user.id, other_user.ap_id)
cm_ref = MessageReference.for_chat_and_object(chat, object)
cm_ref = %{cm_ref | chat: chat, object: object}
Streamer.get_topic_and_add_socket("user", user, oauth_token)
Streamer.stream("user", {user, cm_ref})
text =
StreamerView.render(
"chat_update.json",
%{chat_message_reference: cm_ref},
"user:#{user.id}"
)
assert text =~ "hey cirno"
assert_receive {:text, ^text}
end
test "it sends chat message notifications to the 'user:notification' stream", %{
user: user,
token: oauth_token
} do
other_user = insert(:user)
{:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey")
notify =
Repo.get_by(Pleroma.Notification, user_id: user.id, activity_id: create_activity.id)
|> Repo.preload(:activity)
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
Streamer.stream("user:notification", notify)
assert_receive {:render_with_user, _, _, ^notify, _}
refute Streamer.filtered_by_user?(user, notify)
end
test "it doesn't send notify to the 'user:notification' stream when a user is blocked", %{
user: user,
token: oauth_token
} do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, activity} = CommonAPI.post(user, %{status: ":("})
{:ok, _} = CommonAPI.favorite(activity.id, blocked)
refute_receive _
end
test "it doesn't send notify to the 'user:notification' stream when a thread is muted", %{
user: user,
token: oauth_token
} do
user2 = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
{:ok, _} = CommonAPI.add_mute(activity, user)
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, favorite_activity} = CommonAPI.favorite(activity.id, user2)
refute_receive _
assert Streamer.filtered_by_user?(user, favorite_activity)
end
test "it sends favorite to 'user:notification' stream'", %{
user: user,
token: oauth_token
} do
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, favorite_activity} = CommonAPI.favorite(activity.id, user2)
assert_receive {:render_with_user, _, "notification.json", notif, _}
assert notif.activity.id == favorite_activity.id
refute Streamer.filtered_by_user?(user, notif)
end
test "it doesn't send the 'user:notification' stream' when a domain is blocked", %{
user: user,
token: oauth_token
} do
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
{:ok, user} = User.block_domain(user, "hecking-lewd-place.com")
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, favorite_activity} = CommonAPI.favorite(activity.id, user2)
refute_receive _
assert Streamer.filtered_by_user?(user, favorite_activity)
end
test "it sends follow activities to the 'user:notification' stream", %{
user: user,
token: oauth_token
} do
user2 = insert(:user)
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user, user2)
assert_receive {:render_with_user, _, "notification.json", notif, _}
assert notif.activity.id == follow_activity.id
refute Streamer.filtered_by_user?(user, notif)
end
test "it sends follow relationships updates to the 'user' stream", %{
user: user,
token: oauth_token
} do
user_id = user.id
other_user = insert(:user)
other_user_id = other_user.id
Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(other_user, user)
assert_receive {:text, event}
assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} =
Jason.decode!(event)
assert %{
"follower" => %{
"follower_count" => 0,
"following_count" => 0,
"id" => ^user_id
},
"following" => %{
"follower_count" => 0,
"following_count" => 0,
"id" => ^other_user_id
},
"state" => "follow_pending"
} = Jason.decode!(payload)
assert_receive {:text, event}
assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} =
Jason.decode!(event)
assert %{
"follower" => %{
"follower_count" => 0,
"following_count" => 1,
"id" => ^user_id
},
"following" => %{
"follower_count" => 1,
"following_count" => 0,
"id" => ^other_user_id
},
"state" => "follow_accept"
} = Jason.decode!(payload)
end
test "it streams edits in the 'user' stream", %{user: user, token: oauth_token} do
sender = insert(:user)
{:ok, _, _, _} = CommonAPI.follow(sender, user)
{:ok, activity} = CommonAPI.post(sender, %{status: "hey"})
Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew"})
create = Pleroma.Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"])
assert_receive {:render_with_user, _, "status_update.json", ^create, _}
refute Streamer.filtered_by_user?(user, edited)
end
test "it streams own edits in the 'user' stream", %{user: user, token: oauth_token} do
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, edited} = CommonAPI.update(activity, user, %{status: "mew mew"})
create = Pleroma.Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"])
assert_receive {:render_with_user, _, "status_update.json", ^create, _}
refute Streamer.filtered_by_user?(user, edited)
end
test "it streams posts containing followed hashtags on the 'user' stream", %{
user: user,
token: oauth_token
} do
hashtag = insert(:hashtag, %{name: "tenshi"})
other_user = insert(:user)
{:ok, user} = User.follow_hashtag(user, hashtag)
Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey #tenshi"})
assert_receive {:render_with_user, _, "update.json", ^activity, _}
end
test "should not stream private posts containing followed hashtags on the 'user' stream", %{
user: user,
token: oauth_token
} do
hashtag = insert(:hashtag, %{name: "tenshi"})
other_user = insert(:user)
{:ok, user} = User.follow_hashtag(user, hashtag)
Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, activity} =
CommonAPI.post(other_user, %{status: "hey #tenshi", visibility: "private"})
refute_receive {:render_with_user, _, "update.json", ^activity, _}
end
end
describe "public streams" do
test "it sends to public (authenticated)" do
%{user: user, token: oauth_token} = oauth_access(["read"])
other_user = insert(:user)
Streamer.get_topic_and_add_socket("public", user, oauth_token)
{:ok, activity} = CommonAPI.post(other_user, %{status: "Test"})
assert_receive {:render_with_user, _, _, ^activity, _}
refute Streamer.filtered_by_user?(other_user, activity)
end
test "it sends to public (unauthenticated)" do
user = insert(:user)
Streamer.get_topic_and_add_socket("public", nil, nil)
{:ok, activity} = CommonAPI.post(user, %{status: "Test"})
activity_id = activity.id
assert_receive {:text, event}
assert %{"event" => "update", "payload" => payload} = Jason.decode!(event)
assert %{"id" => ^activity_id} = Jason.decode!(payload)
{:ok, _} = CommonAPI.delete(activity.id, user)
assert_receive {:text, event}
assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
end
test "handles deletions" do
%{user: user, token: oauth_token} = oauth_access(["read"])
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "Test"})
Streamer.get_topic_and_add_socket("public", user, oauth_token)
{:ok, _} = CommonAPI.delete(activity.id, other_user)
activity_id = activity.id
assert_receive {:text, event}
assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
end
test "it streams edits in the 'public' stream" do
sender = insert(:user)
Streamer.get_topic_and_add_socket("public", nil, nil)
{:ok, activity} = CommonAPI.post(sender, %{status: "hey"})
assert_receive {:text, _}
{:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew"})
edited = Pleroma.Activity.normalize(edited)
%{id: activity_id} = Pleroma.Activity.get_create_by_object_ap_id(edited.object.data["id"])
assert_receive {:text, event}
assert %{"event" => "status.update", "payload" => payload} = Jason.decode!(event)
assert %{"id" => ^activity_id} = Jason.decode!(payload)
refute Streamer.filtered_by_user?(sender, edited)
end
test "it streams multiple edits in the 'public' stream correctly" do
sender = insert(:user)
Streamer.get_topic_and_add_socket("public", nil, nil)
{:ok, activity} = CommonAPI.post(sender, %{status: "hey"})
assert_receive {:text, _}
{:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew"})
edited = Pleroma.Activity.normalize(edited)
%{id: activity_id} = Pleroma.Activity.get_create_by_object_ap_id(edited.object.data["id"])
assert_receive {:text, event}
assert %{"event" => "status.update", "payload" => payload} = Jason.decode!(event)
assert %{"id" => ^activity_id} = Jason.decode!(payload)
refute Streamer.filtered_by_user?(sender, edited)
{:ok, edited} = CommonAPI.update(activity, sender, %{status: "mew mew 2"})
edited = Pleroma.Activity.normalize(edited)
%{id: activity_id} = Pleroma.Activity.get_create_by_object_ap_id(edited.object.data["id"])
assert_receive {:text, event}
assert %{"event" => "status.update", "payload" => payload} = Jason.decode!(event)
assert %{"id" => ^activity_id, "content" => "mew mew 2"} = Jason.decode!(payload)
refute Streamer.filtered_by_user?(sender, edited)
end
end
describe "thread_containment/2" do
test "it filters to user if recipients invalid and thread containment is enabled" do
clear_config([:instance, :skip_thread_containment], false)
author = insert(:user)
%{user: user, token: oauth_token} = oauth_access(["read"])
User.follow(user, author, :follow_accept)
activity =
insert(:note_activity,
note:
insert(:note,
user: author,
data: %{"to" => ["TEST-FFF"]}
)
)
Streamer.get_topic_and_add_socket("public", user, oauth_token)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity, _}
assert Streamer.filtered_by_user?(user, activity)
end
test "it sends message if recipients invalid and thread containment is disabled" do
clear_config([:instance, :skip_thread_containment], true)
author = insert(:user)
%{user: user, token: oauth_token} = oauth_access(["read"])
User.follow(user, author, :follow_accept)
activity =
insert(:note_activity,
note:
insert(:note,
user: author,
data: %{"to" => ["TEST-FFF"]}
)
)
Streamer.get_topic_and_add_socket("public", user, oauth_token)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity, _}
refute Streamer.filtered_by_user?(user, activity)
end
test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do
clear_config([:instance, :skip_thread_containment], false)
author = insert(:user)
user = insert(:user, skip_thread_containment: true)
%{token: oauth_token} = oauth_access(["read"], user: user)
User.follow(user, author, :follow_accept)
activity =
insert(:note_activity,
note:
insert(:note,
user: author,
data: %{"to" => ["TEST-FFF"]}
)
)
Streamer.get_topic_and_add_socket("public", user, oauth_token)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity, _}
refute Streamer.filtered_by_user?(user, activity)
end
end
describe "blocks" do
setup do: oauth_access(["read"])
test "it filters messages involving blocked users", %{user: user, token: oauth_token} do
blocked_user = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked_user)
Streamer.get_topic_and_add_socket("public", user, oauth_token)
{:ok, activity} = CommonAPI.post(blocked_user, %{status: "Test"})
assert_receive {:render_with_user, _, _, ^activity, _}
assert Streamer.filtered_by_user?(user, activity)
end
test "it filters messages transitively involving blocked users", %{
user: blocker,
token: blocker_token
} do
blockee = insert(:user)
friend = insert(:user)
Streamer.get_topic_and_add_socket("public", blocker, blocker_token)
{:ok, _user_relationship} = User.block(blocker, blockee)
{:ok, activity_one} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"})
assert_receive {:render_with_user, _, _, ^activity_one, _}
assert Streamer.filtered_by_user?(blocker, activity_one)
{:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
assert_receive {:render_with_user, _, _, ^activity_two, _}
assert Streamer.filtered_by_user?(blocker, activity_two)
{:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"})
assert_receive {:render_with_user, _, _, ^activity_three, _}
assert Streamer.filtered_by_user?(blocker, activity_three)
end
end
describe "lists" do
setup do: oauth_access(["read"])
test "it doesn't send unwanted DMs to list", %{user: user_a, token: user_a_token} do
user_b = insert(:user)
user_c = insert(:user)
{:ok, user_a, user_b} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id})
{:ok, _activity} =
CommonAPI.post(user_b, %{
status: "@#{user_c.nickname} Test",
visibility: "direct"
})
refute_receive _
end
test "it doesn't send unwanted private posts to list", %{user: user_a, token: user_a_token} do
user_b = insert(:user)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id})
{:ok, _activity} =
CommonAPI.post(user_b, %{
status: "Test",
visibility: "private"
})
refute_receive _
end
test "it sends wanted private posts to list", %{user: user_a, token: user_a_token} do
user_b = insert(:user)
{:ok, user_a, user_b} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id})
{:ok, activity} =
CommonAPI.post(user_b, %{
status: "Test",
visibility: "private"
})
assert_receive {:render_with_user, _, _, ^activity, _}
refute Streamer.filtered_by_user?(user_a, activity)
end
end
describe "muted reblogs" do
setup do: oauth_access(["read"])
test "it filters muted reblogs", %{user: user1, token: user1_token} do
user2 = insert(:user)
user3 = insert(:user)
CommonAPI.follow(user2, user1)
CommonAPI.hide_reblogs(user2, user1)
{:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1, user1_token)
{:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, _, ^announce_activity, _}
assert Streamer.filtered_by_user?(user1, announce_activity)
end
test "it filters reblog notification for reblog-muted actors", %{
user: user1,
token: user1_token
} do
user2 = insert(:user)
CommonAPI.follow(user2, user1)
CommonAPI.hide_reblogs(user2, user1)
{:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1, user1_token)
{:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, "notification.json", notif, _}
assert Streamer.filtered_by_user?(user1, notif)
end
- test "it send non-reblog notification for reblog-muted actors", %{
+ test "it sends non-reblog notification for reblog-muted actors", %{
user: user1,
token: user1_token
} do
user2 = insert(:user)
CommonAPI.follow(user2, user1)
CommonAPI.hide_reblogs(user2, user1)
{:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1, user1_token)
{:ok, _favorite_activity} = CommonAPI.favorite(create_activity.id, user2)
assert_receive {:render_with_user, _, "notification.json", notif, _}
refute Streamer.filtered_by_user?(user1, notif)
end
end
describe "muted threads" do
test "it filters posts from muted threads" do
user = insert(:user)
%{user: user2, token: user2_token} = oauth_access(["read"])
Streamer.get_topic_and_add_socket("user", user2, user2_token)
{:ok, user2, user, _activity} = CommonAPI.follow(user, user2)
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
{:ok, _} = CommonAPI.add_mute(activity, user2)
assert_receive {:render_with_user, _, _, ^activity, _}
assert Streamer.filtered_by_user?(user2, activity)
end
end
describe "direct streams" do
setup do: oauth_access(["read"])
test "it sends conversation update to the 'direct' stream", %{user: user, token: oauth_token} do
another_user = insert(:user)
Streamer.get_topic_and_add_socket("direct", user, oauth_token)
{:ok, _create_activity} =
CommonAPI.post(another_user, %{
status: "hey @#{user.nickname}",
visibility: "direct"
})
assert_receive {:text, received_event}
assert %{"event" => "conversation", "payload" => received_payload} =
Jason.decode!(received_event)
assert %{"last_status" => last_status} = Jason.decode!(received_payload)
[participation] = Participation.for_user(user)
assert last_status["pleroma"]["direct_conversation_id"] == participation.id
end
test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted",
%{user: user, token: oauth_token} do
another_user = insert(:user)
Streamer.get_topic_and_add_socket("direct", user, oauth_token)
{:ok, create_activity} =
CommonAPI.post(another_user, %{
status: "hi @#{user.nickname}",
visibility: "direct"
})
create_activity_id = create_activity.id
assert_receive {:render_with_user, _, _, ^create_activity, _}
assert_receive {:text, received_conversation1}
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
{:ok, _} = CommonAPI.delete(create_activity_id, another_user)
assert_receive {:text, received_event}
assert %{"event" => "delete", "payload" => ^create_activity_id} =
Jason.decode!(received_event)
refute_receive _
end
@tag :erratic
test "it sends conversation update to the 'direct' stream when a message is deleted", %{
user: user,
token: oauth_token
} do
another_user = insert(:user)
Streamer.get_topic_and_add_socket("direct", user, oauth_token)
{:ok, create_activity} =
CommonAPI.post(another_user, %{
status: "hi @#{user.nickname}",
visibility: "direct"
})
{:ok, create_activity2} =
CommonAPI.post(another_user, %{
status: "hi @#{user.nickname} 2",
in_reply_to_status_id: create_activity.id,
visibility: "direct"
})
assert_receive {:render_with_user, _, _, ^create_activity, _}
assert_receive {:render_with_user, _, _, ^create_activity2, _}
assert_receive {:text, received_conversation1}
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
assert_receive {:text, received_conversation1}
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
{:ok, _} = CommonAPI.delete(create_activity2.id, another_user)
assert_receive {:text, received_event}
assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
assert_receive {:text, received_event}
assert %{"event" => "conversation", "payload" => received_payload} =
Jason.decode!(received_event)
assert %{"last_status" => last_status} = Jason.decode!(received_payload)
assert last_status["id"] == to_string(create_activity.id)
end
end
describe "stop streaming if token got revoked" do
setup do
child_proc = fn start, finalize ->
fn ->
start.()
receive do
{StreamerTest, :ready} ->
assert_receive {:render_with_user, _, "update.json", _, _}
receive do
{StreamerTest, :revoked} -> finalize.()
end
end
end
end
starter = fn user, token ->
fn -> Streamer.get_topic_and_add_socket("user", user, token) end
end
hit = fn -> assert_receive :close end
miss = fn -> refute_receive :close end
send_all = fn tasks, thing -> Enum.each(tasks, &send(&1.pid, thing)) end
%{
child_proc: child_proc,
starter: starter,
hit: hit,
miss: miss,
send_all: send_all
}
end
test "do not revoke other tokens", %{
child_proc: child_proc,
starter: starter,
hit: hit,
miss: miss,
send_all: send_all
} do
%{user: user, token: token} = oauth_access(["read"])
%{token: token2} = oauth_access(["read"], user: user)
%{user: user2, token: user2_token} = oauth_access(["read"])
post_user = insert(:user)
CommonAPI.follow(post_user, user)
CommonAPI.follow(post_user, user2)
tasks = [
Task.async(child_proc.(starter.(user, token), hit)),
Task.async(child_proc.(starter.(user, token2), miss)),
Task.async(child_proc.(starter.(user2, user2_token), miss))
]
{:ok, _} =
CommonAPI.post(post_user, %{
status: "hi"
})
send_all.(tasks, {StreamerTest, :ready})
Pleroma.Web.OAuth.Token.Strategy.Revoke.revoke(token)
send_all.(tasks, {StreamerTest, :revoked})
Enum.each(tasks, &Task.await/1)
end
test "revoke all streams for this token", %{
child_proc: child_proc,
starter: starter,
hit: hit,
send_all: send_all
} do
%{user: user, token: token} = oauth_access(["read"])
post_user = insert(:user)
CommonAPI.follow(post_user, user)
tasks = [
Task.async(child_proc.(starter.(user, token), hit)),
Task.async(child_proc.(starter.(user, token), hit))
]
{:ok, _} =
CommonAPI.post(post_user, %{
status: "hi"
})
send_all.(tasks, {StreamerTest, :ready})
Pleroma.Web.OAuth.Token.Strategy.Revoke.revoke(token)
send_all.(tasks, {StreamerTest, :revoked})
Enum.each(tasks, &Task.await/1)
end
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Oct 30, 11:41 AM (19 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1800088
Default Alt Text
(79 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline