forked from AkkomaGang/akkoma
Use pseudo ap id of a list in BCC
This commit is contained in:
parent
a3dc02d282
commit
23276e8d68
5 changed files with 92 additions and 24 deletions
|
@ -12,6 +12,8 @@ defmodule Pleroma.List do
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@ap_id_regex ~r/^\/users\/(?<nickname>\w+)\/lists\/(?<list_id>\d+)/
|
||||||
|
|
||||||
schema "lists" do
|
schema "lists" do
|
||||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||||
field(:title, :string)
|
field(:title, :string)
|
||||||
|
@ -32,6 +34,12 @@ def follow_changeset(list, attrs \\ %{}) do
|
||||||
|> validate_required([:following])
|
|> validate_required([:following])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ap_id(%User{nickname: nickname}, list_id) do
|
||||||
|
Pleroma.Web.Endpoint.url() <> "/users/#{nickname}/lists/#{list_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def ap_id({nickname, list_id}), do: ap_id(%User{nickname: nickname}, list_id)
|
||||||
|
|
||||||
def for_user(user, _opts) do
|
def for_user(user, _opts) do
|
||||||
query =
|
query =
|
||||||
from(
|
from(
|
||||||
|
@ -55,6 +63,19 @@ def get(id, %{id: user_id} = _user) do
|
||||||
Repo.one(query)
|
Repo.one(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_by_ap_id(ap_id) do
|
||||||
|
host = Pleroma.Web.Endpoint.host()
|
||||||
|
|
||||||
|
with %{host: ^host, path: path} <- URI.parse(ap_id),
|
||||||
|
%{"list_id" => list_id, "nickname" => nickname} <-
|
||||||
|
Regex.named_captures(@ap_id_regex, path),
|
||||||
|
%User{} = user <- User.get_cached_by_nickname(nickname) do
|
||||||
|
get(list_id, user)
|
||||||
|
else
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_following(%Pleroma.List{following: following} = _list) do
|
def get_following(%Pleroma.List{following: following} = _list) do
|
||||||
q =
|
q =
|
||||||
from(
|
from(
|
||||||
|
@ -125,4 +146,15 @@ def update_follows(%Pleroma.List{} = list, attrs) do
|
||||||
|> follow_changeset(attrs)
|
|> follow_changeset(attrs)
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def memberships(%User{follower_address: follower_address}) do
|
||||||
|
Pleroma.List
|
||||||
|
|> where([l], ^follower_address in l.following)
|
||||||
|
|> join(:inner, [l], u in User, on: l.user_id == u.id)
|
||||||
|
|> select([l, u], {u.nickname, l.id})
|
||||||
|
|> Repo.all()
|
||||||
|
|> Enum.map(&ap_id/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def memberships(_), do: []
|
||||||
end
|
end
|
||||||
|
|
|
@ -783,9 +783,7 @@ defp maybe_preload_objects(query, _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_activities_query(recipients, opts \\ %{}) do
|
def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
base_query = from(activity in Activity)
|
Activity
|
||||||
|
|
||||||
base_query
|
|
||||||
|> maybe_preload_objects(opts)
|
|> maybe_preload_objects(opts)
|
||||||
|> restrict_recipients(recipients, opts["user"])
|
|> restrict_recipients(recipients, opts["user"])
|
||||||
|> restrict_tag(opts)
|
|> restrict_tag(opts)
|
||||||
|
@ -807,9 +805,29 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_activities(recipients, opts \\ %{}) do
|
def fetch_activities(recipients, opts \\ %{}) do
|
||||||
fetch_activities_query(recipients, opts)
|
list_memberships = Pleroma.List.memberships(opts["user"])
|
||||||
|
|
||||||
|
fetch_activities_query(recipients ++ list_memberships, opts)
|
||||||
|> Pagination.fetch_paginated(opts)
|
|> Pagination.fetch_paginated(opts)
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|> maybe_update_cc(list_memberships, opts["user"])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp maybe_update_cc(activities, [], _), do: activities
|
||||||
|
defp maybe_update_cc(activities, _, nil), do: activities
|
||||||
|
|
||||||
|
defp maybe_update_cc(activities, list_memberships, user) do
|
||||||
|
Enum.map(activities, fn
|
||||||
|
%{data: %{"bcc" => bcc}} = activity when is_list(bcc) ->
|
||||||
|
if Enum.any?(bcc, &(&1 in list_memberships)) do
|
||||||
|
update_in(activity.data["cc"], &[user.ap_id | &1])
|
||||||
|
else
|
||||||
|
activity
|
||||||
|
end
|
||||||
|
|
||||||
|
activity ->
|
||||||
|
activity
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
|
def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
|
||||||
|
@ -917,13 +935,23 @@ def should_federate?(inbox, public) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp recipients(actor, activity) do
|
defp recipients(actor, activity) do
|
||||||
Pleroma.Web.Salmon.remote_users(activity) ++
|
followers =
|
||||||
if actor.follower_address in activity.recipients do
|
if actor.follower_address in activity.recipients do
|
||||||
{:ok, followers} = User.get_followers(actor)
|
{:ok, followers} = User.get_followers(actor)
|
||||||
followers |> Enum.filter(&(!&1.local))
|
Enum.filter(followers, &(!&1.local))
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_cc_ap_ids(ap_id, recipients) do
|
||||||
|
host = Map.get(URI.parse(ap_id), :host)
|
||||||
|
|
||||||
|
recipients
|
||||||
|
|> Enum.filter(fn %User{ap_id: ap_id} -> Map.get(URI.parse(ap_id), :host) == host end)
|
||||||
|
|> Enum.map(& &1.ap_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def publish(actor, %{data: %{"bcc" => bcc}} = activity) when is_list(bcc) and bcc != [] do
|
def publish(actor, %{data: %{"bcc" => bcc}} = activity) when is_list(bcc) and bcc != [] do
|
||||||
|
@ -938,12 +966,14 @@ def publish(actor, %{data: %{"bcc" => bcc}} = activity) when is_list(bcc) and bc
|
||||||
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|
||||||
|> Instances.filter_reachable()
|
|> Instances.filter_reachable()
|
||||||
|> Enum.each(fn {inbox, unreachable_since} ->
|
|> Enum.each(fn {inbox, unreachable_since} ->
|
||||||
%User{ap_id: cc} =
|
%User{ap_id: ap_id} =
|
||||||
Enum.find(recipients, fn %{info: %{source_data: data}} -> data["inbox"] == inbox end)
|
Enum.find(recipients, fn %{info: %{source_data: data}} -> data["inbox"] == inbox end)
|
||||||
|
|
||||||
|
cc = get_cc_ap_ids(ap_id, recipients)
|
||||||
|
|
||||||
json =
|
json =
|
||||||
data
|
data
|
||||||
|> Map.put("cc", [cc])
|
|> Map.put("cc", cc)
|
||||||
|> Map.put("directMessage", true)
|
|> Map.put("directMessage", true)
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ def post(user, %{"status" => status} = data) do
|
||||||
visibility
|
visibility
|
||||||
),
|
),
|
||||||
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
|
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
|
||||||
{:ok, bcc} <- bcc_for_list(user, visibility),
|
bcc <- bcc_for_list(user, visibility),
|
||||||
context <- make_context(in_reply_to),
|
context <- make_context(in_reply_to),
|
||||||
cw <- data["spoiler_text"],
|
cw <- data["spoiler_text"],
|
||||||
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
|
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
|
||||||
|
@ -197,7 +197,7 @@ def update(user) do
|
||||||
user =
|
user =
|
||||||
with emoji <- emoji_from_profile(user),
|
with emoji <- emoji_from_profile(user),
|
||||||
source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji),
|
source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji),
|
||||||
info_cng <- Pleroma.User.Info.set_source_data(user.info, source_data),
|
info_cng <- User.Info.set_source_data(user.info, source_data),
|
||||||
change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
|
change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
|
||||||
{:ok, user} <- User.update_and_set_cache(change) do
|
{:ok, user} <- User.update_and_set_cache(change) do
|
||||||
user
|
user
|
||||||
|
@ -230,7 +230,7 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
|
||||||
} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||||
true <- Enum.member?(object_to, "https://www.w3.org/ns/activitystreams#Public"),
|
true <- Enum.member?(object_to, "https://www.w3.org/ns/activitystreams#Public"),
|
||||||
%{valid?: true} = info_changeset <-
|
%{valid?: true} = info_changeset <-
|
||||||
Pleroma.User.Info.add_pinnned_activity(user.info, activity),
|
User.Info.add_pinnned_activity(user.info, activity),
|
||||||
changeset <-
|
changeset <-
|
||||||
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
|
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
|
||||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||||
|
@ -247,7 +247,7 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
|
||||||
def unpin(id_or_ap_id, user) do
|
def unpin(id_or_ap_id, user) do
|
||||||
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||||
%{valid?: true} = info_changeset <-
|
%{valid?: true} = info_changeset <-
|
||||||
Pleroma.User.Info.remove_pinnned_activity(user.info, activity),
|
User.Info.remove_pinnned_activity(user.info, activity),
|
||||||
changeset <-
|
changeset <-
|
||||||
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
|
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
|
||||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||||
|
|
|
@ -8,7 +8,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
alias Pleroma.List
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
@ -106,16 +105,10 @@ def to_for_user_and_mentions(_user, mentions, inReplyTo, "direct") do
|
||||||
def to_for_user_and_mentions(_user, _mentions, _inReplyTo, _), do: {[], []}
|
def to_for_user_and_mentions(_user, _mentions, _inReplyTo, _), do: {[], []}
|
||||||
|
|
||||||
def bcc_for_list(user, {:list, list_id}) do
|
def bcc_for_list(user, {:list, list_id}) do
|
||||||
with {_, %List{} = list} <- {:list, List.get(list_id, user)},
|
[Pleroma.List.ap_id(user, list_id)]
|
||||||
{:ok, following} <- List.get_following(list) do
|
|
||||||
{:ok, Enum.map(following, & &1.ap_id)}
|
|
||||||
else
|
|
||||||
{:list, _} -> {:error, "List not found"}
|
|
||||||
err -> err
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def bcc_for_list(_, _), do: {:ok, []}
|
def bcc_for_list(_, _), do: []
|
||||||
|
|
||||||
def make_content_html(
|
def make_content_html(
|
||||||
status,
|
status,
|
||||||
|
|
|
@ -156,9 +156,22 @@ def encode(private_key, doc) do
|
||||||
{:ok, salmon}
|
{:ok, salmon}
|
||||||
end
|
end
|
||||||
|
|
||||||
def remote_users(%{data: %{"to" => to} = data}) do
|
def remote_users(%User{id: user_id}, %{data: %{"to" => to} = data}) do
|
||||||
cc = Map.get(data, "cc", [])
|
cc = Map.get(data, "cc", [])
|
||||||
bcc = Map.get(data, "bcc", [])
|
|
||||||
|
bcc =
|
||||||
|
data
|
||||||
|
|> Map.get("bcc", [])
|
||||||
|
|> Enum.reduce([], fn ap_id, bcc ->
|
||||||
|
case Pleroma.List.get_by_ap_id(ap_id) do
|
||||||
|
%Pleroma.List{user_id: ^user_id} = list ->
|
||||||
|
{:ok, following} = Pleroma.List.get_following(list)
|
||||||
|
bcc ++ Enum.map(following, & &1.ap_id)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
bcc
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
[to, cc, bcc]
|
[to, cc, bcc]
|
||||||
|> Enum.concat()
|
|> Enum.concat()
|
||||||
|
@ -220,7 +233,7 @@ def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity
|
||||||
{:ok, private, _} = keys_from_pem(keys)
|
{:ok, private, _} = keys_from_pem(keys)
|
||||||
{:ok, feed} = encode(private, feed)
|
{:ok, feed} = encode(private, feed)
|
||||||
|
|
||||||
remote_users = remote_users(activity)
|
remote_users = remote_users(user, activity)
|
||||||
|
|
||||||
salmon_urls = Enum.map(remote_users, & &1.info.salmon)
|
salmon_urls = Enum.map(remote_users, & &1.info.salmon)
|
||||||
reachable_urls_metadata = Instances.filter_reachable(salmon_urls)
|
reachable_urls_metadata = Instances.filter_reachable(salmon_urls)
|
||||||
|
|
Loading…
Reference in a new issue