Merge branch 'explicit-addressing' into 'develop'
Explicit addressing See merge request pleroma/pleroma!1239
This commit is contained in:
commit
e4babb1c9f
|
@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
## [unreleased]
|
||||
### Added
|
||||
- Add a generic settings store for frontends / clients to use.
|
||||
- Explicit addressing option for posting.
|
||||
- Optional SSH access mode. (Needs `erlang-ssh` package on some distributions).
|
||||
- [MongooseIM](https://github.com/esl/MongooseIM) http authentication support.
|
||||
- LDAP authentication
|
||||
|
|
|
@ -70,6 +70,7 @@ 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.
|
||||
|
||||
## PATCH `/api/v1/update_credentials`
|
||||
|
||||
|
|
|
@ -1441,4 +1441,12 @@ def ensure_keys_present(user) do
|
|||
update_and_set_cache(cng)
|
||||
end
|
||||
end
|
||||
|
||||
def get_ap_ids_by_nicknames(nicknames) do
|
||||
from(u in User,
|
||||
where: u.nickname in ^nicknames,
|
||||
select: u.ap_id
|
||||
)
|
||||
|> Repo.all()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -204,8 +204,10 @@ def post(user, %{"status" => status} = data) do
|
|||
data,
|
||||
visibility
|
||||
),
|
||||
mentioned_users <- for({_, mentioned_user} <- mentions, do: mentioned_user.ap_id),
|
||||
addressed_users <- get_addressed_users(mentioned_users, data["to"]),
|
||||
{poll, poll_emoji} <- make_poll_data(data),
|
||||
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
|
||||
{to, cc} <- get_to_and_cc(user, addressed_users, in_reply_to, visibility),
|
||||
context <- make_context(in_reply_to),
|
||||
cw <- data["spoiler_text"] || "",
|
||||
sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}),
|
||||
|
|
|
@ -61,9 +61,9 @@ def attachments_from_ids_descs(ids, descs_str) do
|
|||
end)
|
||||
end
|
||||
|
||||
def to_for_user_and_mentions(user, mentions, inReplyTo, "public") do
|
||||
mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
|
||||
|
||||
@spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) ::
|
||||
{list(String.t()), list(String.t())}
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do
|
||||
to = ["https://www.w3.org/ns/activitystreams#Public" | mentioned_users]
|
||||
cc = [user.follower_address]
|
||||
|
||||
|
@ -74,9 +74,7 @@ def to_for_user_and_mentions(user, mentions, inReplyTo, "public") do
|
|||
end
|
||||
end
|
||||
|
||||
def to_for_user_and_mentions(user, mentions, inReplyTo, "unlisted") do
|
||||
mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
|
||||
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do
|
||||
to = [user.follower_address | mentioned_users]
|
||||
cc = ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
|
||||
|
@ -87,14 +85,12 @@ def to_for_user_and_mentions(user, mentions, inReplyTo, "unlisted") do
|
|||
end
|
||||
end
|
||||
|
||||
def to_for_user_and_mentions(user, mentions, inReplyTo, "private") do
|
||||
{to, cc} = to_for_user_and_mentions(user, mentions, inReplyTo, "direct")
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "private") do
|
||||
{to, cc} = get_to_and_cc(user, mentioned_users, inReplyTo, "direct")
|
||||
{[user.follower_address | to], cc}
|
||||
end
|
||||
|
||||
def to_for_user_and_mentions(_user, mentions, inReplyTo, "direct") do
|
||||
mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
|
||||
|
||||
def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct") do
|
||||
if inReplyTo do
|
||||
{Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []}
|
||||
else
|
||||
|
@ -102,6 +98,12 @@ def to_for_user_and_mentions(_user, mentions, inReplyTo, "direct") do
|
|||
end
|
||||
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 make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data)
|
||||
when is_list(options) do
|
||||
%{max_expiration: max_expiration, min_expiration: min_expiration} =
|
||||
|
|
|
@ -98,6 +98,7 @@ def raw_nodeinfo do
|
|||
"mastodon_api",
|
||||
"mastodon_api_streaming",
|
||||
"polls",
|
||||
"pleroma_explicit_addressing",
|
||||
if Config.get([:media_proxy, :enabled]) do
|
||||
"media_proxy"
|
||||
end,
|
||||
|
|
|
@ -1266,4 +1266,16 @@ test "it doesn't create keys if there already are some" do
|
|||
assert user.info.keys == "xxx"
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_ap_ids_by_nicknames" do
|
||||
test "it returns a list of AP ids for a given set of nicknames" do
|
||||
user = insert(:user)
|
||||
user_two = insert(:user)
|
||||
|
||||
ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
|
||||
assert length(ap_ids) == 2
|
||||
assert user.ap_id in ap_ids
|
||||
assert user_two.ap_id in ap_ids
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,6 +56,25 @@ test "it adds emoji when updating profiles" do
|
|||
end
|
||||
|
||||
describe "posting" do
|
||||
test "it supports explicit addressing" do
|
||||
user = insert(:user)
|
||||
user_two = insert(:user)
|
||||
user_three = insert(:user)
|
||||
user_four = insert(:user)
|
||||
|
||||
{:ok, activity} =
|
||||
CommonAPI.post(user, %{
|
||||
"status" =>
|
||||
"Hey, I think @#{user_three.nickname} is ugly. @#{user_four.nickname} is alright though.",
|
||||
"to" => [user_two.nickname, user_four.nickname, "nonexistent"]
|
||||
})
|
||||
|
||||
assert user.ap_id in activity.recipients
|
||||
assert user_two.ap_id in activity.recipients
|
||||
assert user_four.ap_id in activity.recipients
|
||||
refute user_three.ap_id in activity.recipients
|
||||
end
|
||||
|
||||
test "it filters out obviously bad tags when accepting a post as HTML" do
|
||||
user = insert(:user)
|
||||
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
defmodule Pleroma.Web.CommonAPI.UtilsTest do
|
||||
alias Pleroma.Builders.UserBuilder
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.CommonAPI.Utils
|
||||
alias Pleroma.Web.Endpoint
|
||||
use Pleroma.DataCase
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
@public_address "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
test "it adds attachment links to a given text and attachment set" do
|
||||
name =
|
||||
"Sakura%20Mana%20%E2%80%93%20Turned%20on%20by%20a%20Senior%20OL%20with%20a%20Temptating%20Tight%20Skirt-s%20Full%20Hipline%20and%20Panty%20Shot-%20Beautiful%20Thick%20Thighs-%20and%20Erotic%20Ass-%20-2015-%20--%20Oppaitime%208-28-2017%206-50-33%20PM.png"
|
||||
|
@ -214,4 +219,132 @@ test "when date is nil" do
|
|||
assert Utils.date_to_asctime(nil) == expected
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_to_and_cc" do
|
||||
test "for public posts, not a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public")
|
||||
|
||||
assert length(to) == 2
|
||||
assert length(cc) == 1
|
||||
|
||||
assert @public_address in to
|
||||
assert mentioned_user.ap_id in to
|
||||
assert user.follower_address in cc
|
||||
end
|
||||
|
||||
test "for public posts, a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public")
|
||||
|
||||
assert length(to) == 3
|
||||
assert length(cc) == 1
|
||||
|
||||
assert @public_address in to
|
||||
assert mentioned_user.ap_id in to
|
||||
assert third_user.ap_id in to
|
||||
assert user.follower_address in cc
|
||||
end
|
||||
|
||||
test "for unlisted posts, not a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted")
|
||||
|
||||
assert length(to) == 2
|
||||
assert length(cc) == 1
|
||||
|
||||
assert @public_address in cc
|
||||
assert mentioned_user.ap_id in to
|
||||
assert user.follower_address in to
|
||||
end
|
||||
|
||||
test "for unlisted posts, a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted")
|
||||
|
||||
assert length(to) == 3
|
||||
assert length(cc) == 1
|
||||
|
||||
assert @public_address in cc
|
||||
assert mentioned_user.ap_id in to
|
||||
assert third_user.ap_id in to
|
||||
assert user.follower_address in to
|
||||
end
|
||||
|
||||
test "for private posts, not a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private")
|
||||
|
||||
assert length(to) == 2
|
||||
assert length(cc) == 0
|
||||
|
||||
assert mentioned_user.ap_id in to
|
||||
assert user.follower_address in to
|
||||
end
|
||||
|
||||
test "for private posts, a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private")
|
||||
|
||||
assert length(to) == 3
|
||||
assert length(cc) == 0
|
||||
|
||||
assert mentioned_user.ap_id in to
|
||||
assert third_user.ap_id in to
|
||||
assert user.follower_address in to
|
||||
end
|
||||
|
||||
test "for direct posts, not a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct")
|
||||
|
||||
assert length(to) == 1
|
||||
assert length(cc) == 0
|
||||
|
||||
assert mentioned_user.ap_id in to
|
||||
end
|
||||
|
||||
test "for direct posts, a reply" do
|
||||
user = insert(:user)
|
||||
mentioned_user = insert(:user)
|
||||
third_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
|
||||
mentions = [mentioned_user.ap_id]
|
||||
|
||||
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct")
|
||||
|
||||
assert length(to) == 2
|
||||
assert length(cc) == 0
|
||||
|
||||
assert mentioned_user.ap_id in to
|
||||
assert third_user.ap_id in to
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue