Add `local` visibility
This commit is contained in:
parent
c7bcbfbc1d
commit
0118ccb53c
|
@ -14,7 +14,7 @@ Adding the parameter `reply_visibility` to the public and home timelines queries
|
|||
|
||||
## Statuses
|
||||
|
||||
- `visibility`: has an additional possible value `list`
|
||||
- `visibility`: has additional possible values `list` and `local` (for local-only statuses)
|
||||
|
||||
Has these additional fields under the `pleroma` object:
|
||||
|
||||
|
@ -28,7 +28,6 @@ Has these additional fields under the `pleroma` object:
|
|||
- `thread_muted`: true if the thread the post belongs to is muted
|
||||
- `emoji_reactions`: A list with emoji / reaction maps. The format is `{name: "☕", count: 1, me: true}`. Contains no information about the reacting users, for that use the `/statuses/:id/reactions` endpoint.
|
||||
- `parent_visible`: If the parent of this post is visible to the user or not.
|
||||
- `local_only`: true for local-only, non-federated posts.
|
||||
|
||||
## Media Attachments
|
||||
|
||||
|
@ -152,10 +151,9 @@ Additional parameters can be added to the JSON body/Form data:
|
|||
- `preview`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
|
||||
- `content_type`: string, contain the MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint.
|
||||
- `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply.
|
||||
- `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`.
|
||||
- `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted`, `local` or `public`) it can be used to address a List by setting it to `list:LIST_ID`.
|
||||
- `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour.
|
||||
- `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`.
|
||||
- `local_only`: boolean, if set to `true` the post won't be federated.
|
||||
|
||||
## GET `/api/v1/statuses`
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@ defmodule Pleroma.Activity do
|
|||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
@type actor :: String.t()
|
||||
|
||||
|
@ -358,12 +356,4 @@ def pinned_by_actor?(%Activity{} = activity) do
|
|||
actor = user_actor(activity)
|
||||
activity.id in actor.pinned_activities
|
||||
end
|
||||
|
||||
def local_only?(activity) do
|
||||
recipients = Enum.concat(activity.data["to"], Map.get(activity.data, "cc", []))
|
||||
public = Pleroma.Constants.as_public()
|
||||
local = Pleroma.Constants.as_local_public()
|
||||
|
||||
Enum.member?(recipients, local) and not Enum.member?(recipients, public)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -222,7 +222,7 @@ def announce(actor, object, options \\ []) do
|
|||
actor.ap_id == Relay.ap_id() ->
|
||||
[actor.follower_address]
|
||||
|
||||
public? and Pleroma.Activity.local_only?(object) ->
|
||||
public? and Visibility.is_local_public?(object) ->
|
||||
[actor.follower_address, object.data["actor"], Pleroma.Constants.as_local_public()]
|
||||
|
||||
public? ->
|
||||
|
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
|
|||
alias Pleroma.Web.ActivityPub.MRF
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidator
|
||||
alias Pleroma.Web.ActivityPub.SideEffects
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.Federator
|
||||
|
||||
@spec common_pipeline(map(), keyword()) ::
|
||||
|
@ -55,7 +56,7 @@ defp maybe_federate(%Activity{} = activity, meta) do
|
|||
with {:ok, local} <- Keyword.fetch(meta, :local) do
|
||||
do_not_federate = meta[:do_not_federate] || !Config.get([:instance, :federating])
|
||||
|
||||
if !do_not_federate and local and not Activity.local_only?(activity) do
|
||||
if !do_not_federate and local and not Visibility.is_local_public?(activity) do
|
||||
activity =
|
||||
if object = Keyword.get(meta, :object_data) do
|
||||
%{activity | data: Map.put(activity.data, "object", object)}
|
||||
|
|
|
@ -176,7 +176,7 @@ def maybe_federate(%Activity{local: true, data: %{"type" => type}} = activity) d
|
|||
|
||||
with true <- Config.get!([:instance, :federating]),
|
||||
true <- type != "Block" || outgoing_blocks,
|
||||
false <- Activity.local_only?(activity) do
|
||||
false <- Visibility.is_local_public?(activity) do
|
||||
Pleroma.Web.Federator.publish(activity)
|
||||
end
|
||||
|
||||
|
|
|
@ -23,6 +23,14 @@ def is_public?(data) do
|
|||
Utils.label_in_message?(Pleroma.Constants.as_local_public(), data)
|
||||
end
|
||||
|
||||
def is_local_public?(%Object{data: data}), do: is_local_public?(data)
|
||||
def is_local_public?(%Activity{data: data}), do: is_local_public?(data)
|
||||
|
||||
def is_local_public?(data) do
|
||||
Utils.label_in_message?(Pleroma.Constants.as_local_public(), data) and
|
||||
not Utils.label_in_message?(Pleroma.Constants.as_public(), data)
|
||||
end
|
||||
|
||||
def is_private?(activity) do
|
||||
with false <- is_public?(activity),
|
||||
%User{follower_address: follower_address} <-
|
||||
|
@ -118,6 +126,9 @@ def get_visibility(object) do
|
|||
Pleroma.Constants.as_public() in cc ->
|
||||
"unlisted"
|
||||
|
||||
Pleroma.Constants.as_local_public() in to ->
|
||||
"local"
|
||||
|
||||
# this should use the sql for the object's activity
|
||||
Enum.any?(to, &String.contains?(&1, "/followers")) ->
|
||||
"private"
|
||||
|
|
|
@ -475,10 +475,6 @@ defp create_request do
|
|||
type: :string,
|
||||
description:
|
||||
"Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`."
|
||||
},
|
||||
local_only: %Schema{
|
||||
type: :boolean,
|
||||
description: "Post the status as local only"
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
|
|
|
@ -9,6 +9,6 @@ defmodule Pleroma.Web.ApiSpec.Schemas.VisibilityScope do
|
|||
title: "VisibilityScope",
|
||||
description: "Status visibility",
|
||||
type: :string,
|
||||
enum: ["public", "unlisted", "private", "direct", "list"]
|
||||
enum: ["public", "unlisted", "local", "private", "direct", "list"]
|
||||
})
|
||||
end
|
||||
|
|
|
@ -359,7 +359,7 @@ def public_announce?(object, _) do
|
|||
def get_visibility(_, _, %Participation{}), do: {"direct", "direct"}
|
||||
|
||||
def get_visibility(%{visibility: visibility}, in_reply_to, _)
|
||||
when visibility in ~w{public unlisted private direct},
|
||||
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
|
||||
|
|
|
@ -65,8 +65,14 @@ def get_to_and_cc(%{in_reply_to_conversation: %Participation{} = participation})
|
|||
{Enum.map(participation.recipients, & &1.ap_id), []}
|
||||
end
|
||||
|
||||
def get_to_and_cc(%{visibility: "public"} = draft) do
|
||||
to = [public_uri(draft) | draft.mentions]
|
||||
def get_to_and_cc(%{visibility: visibility} = draft) when visibility in ["public", "local"] do
|
||||
|
||||
to =
|
||||
case visibility do
|
||||
"public" -> [Pleroma.Constants.as_public() | draft.mentions]
|
||||
"local" -> [Pleroma.Constants.as_local_public() | draft.mentions]
|
||||
end
|
||||
|
||||
cc = [draft.user.follower_address]
|
||||
|
||||
if draft.in_reply_to do
|
||||
|
@ -78,7 +84,7 @@ def get_to_and_cc(%{visibility: "public"} = draft) do
|
|||
|
||||
def get_to_and_cc(%{visibility: "unlisted"} = draft) do
|
||||
to = [draft.user.follower_address | draft.mentions]
|
||||
cc = [public_uri(draft)]
|
||||
cc = [Pleroma.Constants.as_public()]
|
||||
|
||||
if draft.in_reply_to do
|
||||
{Enum.uniq([draft.in_reply_to.data["actor"] | to]), cc}
|
||||
|
@ -103,9 +109,6 @@ def get_to_and_cc(%{visibility: "direct"} = draft) do
|
|||
|
||||
def get_to_and_cc(%{visibility: {:list, _}, mentions: mentions}), do: {mentions, []}
|
||||
|
||||
defp public_uri(%{params: %{local_only: true}}), do: Pleroma.Constants.as_local_public()
|
||||
defp public_uri(_), do: Pleroma.Constants.as_public()
|
||||
|
||||
def get_addressed_users(_, to) when is_list(to) do
|
||||
User.get_ap_ids_by_nicknames(to)
|
||||
end
|
||||
|
|
|
@ -368,8 +368,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
|||
direct_conversation_id: direct_conversation_id,
|
||||
thread_muted: thread_muted?,
|
||||
emoji_reactions: emoji_reactions,
|
||||
parent_visible: visible_for_user?(reply_to, opts[:for]),
|
||||
local_only: Activity.local_only?(activity)
|
||||
parent_visible: visible_for_user?(reply_to, opts[:for])
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1256,16 +1256,16 @@ test "fallback" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "with `local_only` enabled" do
|
||||
describe "with `local` visibility" do
|
||||
setup do: clear_config([:instance, :federating], true)
|
||||
|
||||
test "post" do
|
||||
user = insert(:user)
|
||||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", local_only: true})
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert_not_called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1274,13 +1274,13 @@ test "delete" do
|
|||
user = insert(:user)
|
||||
|
||||
{:ok, %Activity{id: activity_id}} =
|
||||
CommonAPI.post(user, %{status: "#2hu #2HU", local_only: true})
|
||||
CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
|
||||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} =
|
||||
CommonAPI.delete(activity_id, user)
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
assert_not_called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1290,13 +1290,13 @@ test "repeat" do
|
|||
other_user = insert(:user)
|
||||
|
||||
{:ok, %Activity{id: activity_id}} =
|
||||
CommonAPI.post(other_user, %{status: "cofe", local_only: true})
|
||||
CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
||||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} =
|
||||
CommonAPI.repeat(activity_id, user)
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1306,7 +1306,7 @@ test "unrepeat" do
|
|||
other_user = insert(:user)
|
||||
|
||||
{:ok, %Activity{id: activity_id}} =
|
||||
CommonAPI.post(other_user, %{status: "cofe", local_only: true})
|
||||
CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
||||
|
||||
assert {:ok, _} = CommonAPI.repeat(activity_id, user)
|
||||
|
||||
|
@ -1314,7 +1314,7 @@ test "unrepeat" do
|
|||
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
|
||||
CommonAPI.unrepeat(activity_id, user)
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1323,13 +1323,13 @@ test "favorite" do
|
|||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", local_only: true})
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
||||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} =
|
||||
CommonAPI.favorite(user, activity.id)
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1338,13 +1338,13 @@ test "unfavorite" do
|
|||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", local_only: true})
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
||||
|
||||
{:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
|
||||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user)
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1352,13 +1352,13 @@ test "unfavorite" do
|
|||
test "react_with_emoji" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", local_only: true})
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
||||
|
||||
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
||||
assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} =
|
||||
CommonAPI.react_with_emoji(activity.id, user, "👍")
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
@ -1366,7 +1366,7 @@ test "react_with_emoji" do
|
|||
test "unreact_with_emoji" do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", local_only: true})
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
||||
|
||||
{:ok, _reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
|
||||
|
||||
|
@ -1374,7 +1374,7 @@ test "unreact_with_emoji" do
|
|||
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
|
||||
CommonAPI.unreact_with_emoji(activity.id, user, "👍")
|
||||
|
||||
assert Activity.local_only?(activity)
|
||||
assert Visibility.is_local_public?(activity)
|
||||
refute called(Pleroma.Web.Federator.publish(activity))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1749,12 +1749,12 @@ test "posting a local only status" do
|
|||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses", %{
|
||||
"status" => "cofe",
|
||||
"local_only" => "true"
|
||||
"visibility" => "local"
|
||||
})
|
||||
|
||||
local = Pleroma.Constants.as_local_public()
|
||||
|
||||
assert %{"content" => "cofe", "id" => id, "pleroma" => %{"local_only" => true}} =
|
||||
assert %{"content" => "cofe", "id" => id, "visibility" => "local"} =
|
||||
json_response(conn_one, 200)
|
||||
|
||||
assert %Activity{id: ^id, data: %{"to" => [^local]}} = Activity.get_by_id(id)
|
||||
|
|
|
@ -245,8 +245,7 @@ test "a note activity" do
|
|||
direct_conversation_id: nil,
|
||||
thread_muted: false,
|
||||
emoji_reactions: [],
|
||||
parent_visible: false,
|
||||
local_only: false
|
||||
parent_visible: false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue