Drop broken list addressing feature
This feature was both conceptually broken and through bitrotting the implementation was also buggy with the handling of certain list-post interactions just crashing. Remote servers had no way to know who belongs to a list and thus posts basically showed just up as weird DM threads with different participants on each instance. And while on the local instance addition and removal from a listed grated and revoked post access retroactively, it never acted retroactively on remotes. Notably our "activity_visibility" database function also didn’t know about "list visibility" instead treating them as direct messages. Furthermore no known client actualy allows creating such messages and the lack of complaints about the accumulutaed bugs supports the absence of any users. Given this there seems no point in fixing the implementation. To reduce complexity of visibility handling it will be dropped instead. Note, a similar effect with less federation weirdness can already be achieved client-side using the explicit-addressing feature originally introduced in https://git.pleroma.social/pleroma/pleroma/-/merge_requests/1239. Ref: https://akkoma.dev/AkkomaGang/akkoma/issues/812
This commit is contained in:
parent
d96c6f438d
commit
271110c1a5
12 changed files with 39 additions and 122 deletions
|
|
@ -32,7 +32,7 @@ Home, public, hashtag & list timelines further accept:
|
|||
|
||||
## Statuses
|
||||
|
||||
- `visibility`: has additional possible values `list` and `local` (for local-only statuses)
|
||||
- `visibility`: has additional possible value `local` (for local-only statuses)
|
||||
- `emoji_reactions`: additional field since Akkoma 3.2.0; identical to `pleroma/emoji_reactions`
|
||||
|
||||
Has these additional fields under the `pleroma` object:
|
||||
|
|
|
|||
|
|
@ -267,17 +267,33 @@ special meaning to the potential local-scope identifier.
|
|||
however those are also shown publicly on the local web interface
|
||||
and are thus visible to non-members.
|
||||
|
||||
## List post scope
|
||||
|
||||
Messages originally addressed to a custom list will contain
|
||||
a `listMessage` field with an unresolvable pseudo ActivityPub id.
|
||||
|
||||
# Deprecated and Removed Extensions
|
||||
|
||||
The following extensions were used in the past but have been dropped.
|
||||
Documentation is retained here as a reference and since old objects might
|
||||
still contains related fields.
|
||||
|
||||
## List post scope
|
||||
|
||||
Messages originally addressed to a custom list will contain
|
||||
a `listMessage` field with an unresolvable pseudo ActivityPub id.
|
||||
|
||||
!!! note
|
||||
The concept did not work out too well in practice with even remote servers
|
||||
recognising the `listMessage` extension being unaware of the state of the
|
||||
list and resulting weird desyncs in thread display and handling between
|
||||
servers.
|
||||
As it was it also never found its way in any known clients or frontends.
|
||||
|
||||
A more consistent superset of what this was able to actually do
|
||||
can be achieved without ActivityPub extensions by explicitly addressing
|
||||
all intended participants without inline mentions.
|
||||
While true federated and moderated "lists" or "groups"
|
||||
will need more work and a different approach.
|
||||
|
||||
Thus suport for it was removed and it is recommended
|
||||
to not create any new implementation of it.
|
||||
|
||||
## Actor endpoints
|
||||
|
||||
The following endpoints used to be present:
|
||||
|
|
|
|||
|
|
@ -53,25 +53,11 @@ def is_direct?(activity) do
|
|||
!is_public?(activity) && !is_private?(activity)
|
||||
end
|
||||
|
||||
def is_list?(%{data: %{"listMessage" => _}}), do: true
|
||||
def is_list?(_), do: false
|
||||
|
||||
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
|
||||
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false
|
||||
def visible_for_user?(%Activity{actor: ap_id}, %User{ap_id: ap_id}), do: true
|
||||
def visible_for_user?(%Object{data: %{"actor" => ap_id}}, %User{ap_id: ap_id}), do: true
|
||||
def visible_for_user?(nil, _), do: false
|
||||
def visible_for_user?(%Activity{data: %{"listMessage" => _}}, nil), do: false
|
||||
|
||||
def visible_for_user?(
|
||||
%Activity{data: %{"listMessage" => list_ap_id}} = activity,
|
||||
%User{} = user
|
||||
) do
|
||||
user.ap_id in activity.data["to"] ||
|
||||
list_ap_id
|
||||
|> Pleroma.List.get_by_ap_id()
|
||||
|> Pleroma.List.member?(user)
|
||||
end
|
||||
|
||||
def visible_for_user?(%{__struct__: module} = message, nil)
|
||||
when module in [Activity, Object] do
|
||||
|
|
@ -141,9 +127,6 @@ def get_visibility(object) do
|
|||
object.data["directMessage"] == true ->
|
||||
"direct"
|
||||
|
||||
is_binary(object.data["listMessage"]) ->
|
||||
"list"
|
||||
|
||||
length(cc) > 0 ->
|
||||
"private"
|
||||
|
||||
|
|
|
|||
|
|
@ -553,10 +553,9 @@ defp create_request do
|
|||
nullable: true,
|
||||
anyOf: [
|
||||
VisibilityScope,
|
||||
%Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
|
||||
%Schema{type: :string, description: "scope name", example: "unlisted"}
|
||||
],
|
||||
description:
|
||||
"Visibility of the posted status. Besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`"
|
||||
description: "Visibility of the posted status."
|
||||
},
|
||||
expires_in: %Schema{
|
||||
nullable: true,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ defmodule Pleroma.Web.ApiSpec.Schemas.VisibilityScope do
|
|||
title: "VisibilityScope",
|
||||
description: "Status visibility",
|
||||
type: :string,
|
||||
enum: ["public", "unlisted", "local", "private", "direct", "list"]
|
||||
enum: ["public", "unlisted", "local", "private", "direct"]
|
||||
})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -300,11 +300,6 @@ def get_visibility(%{visibility: visibility}, in_reply_to, _)
|
|||
when visibility in ~w{public local unlisted private direct},
|
||||
do: {visibility, get_replied_to_visibility(in_reply_to)}
|
||||
|
||||
def get_visibility(%{visibility: "list:" <> list_id}, in_reply_to, _) do
|
||||
visibility = {:list, String.to_integer(list_id)}
|
||||
{visibility, get_replied_to_visibility(in_reply_to)}
|
||||
end
|
||||
|
||||
def get_visibility(_, in_reply_to, _) when not is_nil(in_reply_to) do
|
||||
visibility = get_replied_to_visibility(in_reply_to)
|
||||
{visibility, visibility}
|
||||
|
|
|
|||
|
|
@ -298,7 +298,6 @@ defp changes(draft) do
|
|||
object: draft.object,
|
||||
additional: additional
|
||||
}
|
||||
|> Utils.maybe_add_list_data(draft.user, draft.visibility)
|
||||
|
||||
%__MODULE__{draft | changes: changes}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -118,31 +118,12 @@ def get_to_and_cc_for_visibility("direct", _, _, mentions) do
|
|||
{mentions, []}
|
||||
end
|
||||
|
||||
def get_to_and_cc_for_visibility({:list, _}, _, _, mentions) do
|
||||
{mentions, []}
|
||||
end
|
||||
|
||||
def get_addressed_users(_, to) when is_list(to) do
|
||||
User.get_ap_ids_by_nicknames(to)
|
||||
end
|
||||
|
||||
def get_addressed_users(mentioned_users, _), do: mentioned_users
|
||||
|
||||
def maybe_add_list_data(activity_params, user, {:list, list_id}) do
|
||||
case Pleroma.List.get(list_id, user) do
|
||||
%Pleroma.List{} = list ->
|
||||
activity_params
|
||||
|> put_in([:additional, "bcc"], [list.ap_id])
|
||||
|> put_in([:additional, "listMessage"], list.ap_id)
|
||||
|> put_in([:object, "listMessage"], list.ap_id)
|
||||
|
||||
_ ->
|
||||
activity_params
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_add_list_data(activity_params, _, _), do: activity_params
|
||||
|
||||
def make_poll_data(%{"poll" => %{"expires_in" => expires_in}} = data)
|
||||
when is_binary(expires_in) do
|
||||
# In some cases mastofe sends out strings instead of integers
|
||||
|
|
|
|||
|
|
@ -36,12 +36,18 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
|
|||
|
||||
{:ok, local} = CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "local"})
|
||||
|
||||
{:ok, list} =
|
||||
# list visibility is no longer supported, but we want to check any
|
||||
# leftover entreis are handled sensibly, so we nned to manually fix up the data
|
||||
{:ok, list_activity} =
|
||||
CommonAPI.post(user, %{
|
||||
status: "@#{mentioned.nickname}",
|
||||
visibility: "list:#{list.id}"
|
||||
visibility: "direct"
|
||||
})
|
||||
|
||||
list_object = Object.normalize(list_activity)
|
||||
{:ok, list_object} = Object.update_data(list_object, %{"listMessage" => list.ap_id})
|
||||
list_activity = %Activity{list_activity | object: list_object}
|
||||
|
||||
%{
|
||||
public: public,
|
||||
private: private,
|
||||
|
|
@ -51,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
|
|||
mentioned: mentioned,
|
||||
following: following,
|
||||
unrelated: unrelated,
|
||||
list: list,
|
||||
list: list_activity,
|
||||
local: local,
|
||||
remote: remote
|
||||
}
|
||||
|
|
@ -69,8 +75,8 @@ test "is_direct?", %{
|
|||
refute Visibility.is_direct?(public)
|
||||
refute Visibility.is_direct?(private)
|
||||
refute Visibility.is_direct?(unlisted)
|
||||
assert Visibility.is_direct?(list)
|
||||
refute Visibility.is_direct?(local)
|
||||
assert Visibility.is_direct?(list)
|
||||
end
|
||||
|
||||
test "is_public?", %{
|
||||
|
|
@ -105,22 +111,6 @@ test "is_private?", %{
|
|||
refute Visibility.is_private?(local)
|
||||
end
|
||||
|
||||
test "is_list?", %{
|
||||
public: public,
|
||||
private: private,
|
||||
direct: direct,
|
||||
unlisted: unlisted,
|
||||
list: list,
|
||||
local: local
|
||||
} do
|
||||
refute Visibility.is_list?(direct)
|
||||
refute Visibility.is_list?(public)
|
||||
refute Visibility.is_list?(private)
|
||||
refute Visibility.is_list?(unlisted)
|
||||
assert Visibility.is_list?(list)
|
||||
refute Visibility.is_list?(local)
|
||||
end
|
||||
|
||||
test "visible_for_user? Activity", %{
|
||||
public: public,
|
||||
private: private,
|
||||
|
|
@ -177,9 +167,6 @@ test "visible_for_user? Activity", %{
|
|||
refute Visibility.visible_for_user?(direct, nil)
|
||||
refute Visibility.visible_for_user?(local, nil)
|
||||
|
||||
# Visible for a list member
|
||||
assert Visibility.visible_for_user?(list, unrelated)
|
||||
|
||||
# Local not visible to remote user
|
||||
refute Visibility.visible_for_user?(local, remote)
|
||||
end
|
||||
|
|
@ -270,15 +257,16 @@ test "get_visibility", %{
|
|||
assert Visibility.get_visibility(private) == "private"
|
||||
assert Visibility.get_visibility(direct) == "direct"
|
||||
assert Visibility.get_visibility(unlisted) == "unlisted"
|
||||
assert Visibility.get_visibility(list) == "list"
|
||||
# legacy, no longer supported visibility type doesn't leak out now
|
||||
assert Visibility.get_visibility(list) == "direct"
|
||||
end
|
||||
|
||||
test "get_visibility with directMessage flag" do
|
||||
assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct"
|
||||
end
|
||||
|
||||
test "get_visibility with listMessage flag" do
|
||||
assert Visibility.get_visibility(%{data: %{"listMessage" => ""}}) == "list"
|
||||
test "get_visibility treats legacy list messages as direct" do
|
||||
assert Visibility.get_visibility(%{data: %{"listMessage" => ""}}) == "direct"
|
||||
end
|
||||
|
||||
describe "entire_thread_visible_for_user?/2" do
|
||||
|
|
|
|||
|
|
@ -609,27 +609,6 @@ test "returns [] when not pass media_ids" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "maybe_add_list_data/3" do
|
||||
test "adds list params when found user list" do
|
||||
user = insert(:user)
|
||||
{:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user)
|
||||
|
||||
assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
|
||||
%{
|
||||
additional: %{"bcc" => [list.ap_id], "listMessage" => list.ap_id},
|
||||
object: %{"listMessage" => list.ap_id}
|
||||
}
|
||||
end
|
||||
|
||||
test "returns original params when list not found" do
|
||||
user = insert(:user)
|
||||
{:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user))
|
||||
|
||||
assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
|
||||
%{additional: %{}, object: %{}}
|
||||
end
|
||||
end
|
||||
|
||||
describe "maybe_add_attachments/3" do
|
||||
test "returns parsed results when attachment_links is false" do
|
||||
assert Utils.maybe_add_attachments(
|
||||
|
|
|
|||
|
|
@ -543,17 +543,6 @@ test "replying with a direct message will NOT auto-add the author of the reply t
|
|||
refute user.ap_id in secret_answer.recipients
|
||||
end
|
||||
|
||||
test "it allows to address a list" do
|
||||
user = insert(:user)
|
||||
{:ok, list} = Pleroma.List.create("foo", user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
|
||||
|
||||
assert activity.data["bcc"] == [list.ap_id]
|
||||
assert activity.recipients == [list.ap_id, user.ap_id]
|
||||
assert activity.data["listMessage"] == list.ap_id
|
||||
end
|
||||
|
||||
test "it adds the htmlMFM term to MFM posts and properly processes it" do
|
||||
user = insert(:user)
|
||||
|
||||
|
|
|
|||
|
|
@ -942,18 +942,6 @@ test "does not embed a relationship in the account in reposts" do
|
|||
assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
|
||||
end
|
||||
|
||||
test "visibility/list" do
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, list} = Pleroma.List.create("foo", user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
|
||||
|
||||
status = StatusView.render("show.json", activity: activity)
|
||||
|
||||
assert status.visibility == "list"
|
||||
end
|
||||
|
||||
test "has a field for parent visibility" do
|
||||
user = insert(:user)
|
||||
poster = insert(:user)
|
||||
|
|
|
|||
Loading…
Reference in a new issue