Page MenuHomePhorge

No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None
diff --git a/changelog.d/mrf-fodirectreply.add b/changelog.d/mrf-fodirectreply.add
index c144e1bc0..10fd5d16a 100644
--- a/changelog.d/mrf-fodirectreply.add
+++ b/changelog.d/mrf-fodirectreply.add
@@ -1 +1 @@
-Added MRF.FODirectReply which changes replies to followers-only posts to be direct
+Added MRF.FODirectReply which changes replies to followers-only posts to be direct.
diff --git a/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex b/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
index 4eb97afa8..2cf22745a 100644
--- a/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
+++ b/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
@@ -1,65 +1,53 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.FODirectReply do
@moduledoc """
FODirectReply alters the scope of replies to activities which are Followers Only to be Direct. The purpose of this policy is to prevent broken threads for followers of the reply author because their response was to a user that they are not also following.
"""
+ alias Pleroma.Object
alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Visibility
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(
%{
"type" => "Create",
"to" => to,
"object" => %{
"actor" => actor,
"type" => "Note",
"inReplyTo" => in_reply_to
}
} = activity
) do
with true <- is_binary(in_reply_to),
%User{follower_address: followers_collection, local: true} <- User.get_by_ap_id(actor),
- true <- followers_only?(in_reply_to) do
+ %Object{} = in_reply_to_object <- Object.get_by_ap_id(in_reply_to),
+ "private" <- Visibility.get_visibility(in_reply_to_object) do
direct_to = to -- [followers_collection]
updated_activity =
activity
|> Map.put("cc", [])
|> Map.put("to", direct_to)
|> Map.put("directMessage", true)
|> put_in(["object", "cc"], [])
|> put_in(["object", "to"], direct_to)
{:ok, updated_activity}
else
_ -> {:ok, activity}
end
end
@impl true
def filter(activity), do: {:ok, activity}
@impl true
def describe, do: {:ok, %{}}
-
- defp followers_only?(parent_ap_id) do
- with %Pleroma.Object{} = object <- Pleroma.Object.get_by_ap_id(parent_ap_id),
- object_data <- Map.get(object, :data),
- %Pleroma.User{} = user <- User.get_cached_by_ap_id(object_data["actor"]) do
- if user.follower_address in object_data["to"] do
- true
- else
- false
- end
- else
- _ ->
- false
- end
- end
end
diff --git a/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs b/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs
index 7afc83ffc..2d6af3b68 100644
--- a/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/fo_direct_reply_test.exs
@@ -1,87 +1,117 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.FODirectReplyTest do
use Pleroma.DataCase
import Pleroma.Factory
require Pleroma.Constants
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.MRF.FODirectReply
alias Pleroma.Web.CommonAPI
test "replying to followers-only/private is changed to direct" do
batman = insert(:user, nickname: "batman")
robin = insert(:user, nickname: "robin")
{:ok, post} =
CommonAPI.post(batman, %{
status: "Has anyone seen Selina Kyle's latest selfies?",
visibility: "private"
})
reply = %{
"type" => "Create",
"actor" => robin.ap_id,
"to" => [batman.ap_id, robin.follower_address],
"cc" => [],
"object" => %{
"type" => "Note",
"actor" => robin.ap_id,
"content" => "@batman 🤤 ❤️ 🐈‍⬛",
"to" => [batman.ap_id, robin.follower_address],
"cc" => [],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
expected_to = [batman.ap_id]
expected_cc = []
assert {:ok, filtered} = FODirectReply.filter(reply)
assert expected_to == filtered["to"]
assert expected_cc == filtered["cc"]
assert expected_to == filtered["object"]["to"]
assert expected_cc == filtered["object"]["cc"]
end
+ test "replies to unlisted posts are unmodified" do
+ batman = insert(:user, nickname: "batman")
+ robin = insert(:user, nickname: "robin")
+
+ {:ok, post} =
+ CommonAPI.post(batman, %{
+ status: "Has anyone seen Selina Kyle's latest selfies?",
+ visibility: "unlisted"
+ })
+
+ reply = %{
+ "type" => "Create",
+ "actor" => robin.ap_id,
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "object" => %{
+ "type" => "Note",
+ "actor" => robin.ap_id,
+ "content" => "@batman 🤤 ❤️ 🐈<200d>⬛",
+ "to" => [batman.ap_id, robin.follower_address],
+ "cc" => [],
+ "inReplyTo" => Object.normalize(post).data["id"]
+ }
+ }
+
+ assert {:ok, filtered} = FODirectReply.filter(reply)
+
+ assert match?(^filtered, reply)
+ end
+
test "replies to public posts are unmodified" do
batman = insert(:user, nickname: "batman")
robin = insert(:user, nickname: "robin")
{:ok, post} =
CommonAPI.post(batman, %{status: "Has anyone seen Selina Kyle's latest selfies?"})
reply = %{
"type" => "Create",
"actor" => robin.ap_id,
"to" => [batman.ap_id, robin.follower_address],
"cc" => [],
"object" => %{
"type" => "Note",
"actor" => robin.ap_id,
"content" => "@batman 🤤 ❤️ 🐈<200d>⬛",
"to" => [batman.ap_id, robin.follower_address],
"cc" => [],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
assert {:ok, filtered} = FODirectReply.filter(reply)
assert match?(^filtered, reply)
end
test "non-reply posts are unmodified" do
batman = insert(:user, nickname: "batman")
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
assert {:ok, filtered} = FODirectReply.filter(post)
assert match?(^filtered, post)
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Aug 8, 12:25 PM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1723247
Default Alt Text
(6 KB)

Event Timeline