Merge branch 'develop' into issue/1342

This commit is contained in:
Maksim Pechnikov 2019-12-05 15:46:27 +03:00
commit 3fe7a1fd35
36 changed files with 563 additions and 84 deletions

View file

@ -28,7 +28,8 @@ defmodule Pleroma.Activity do
"Create" => "mention",
"Follow" => "follow",
"Announce" => "reblog",
"Like" => "favourite"
"Like" => "favourite",
"Move" => "move"
}
@mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types,

View file

@ -107,4 +107,22 @@ defmodule Pleroma.FollowingRelationship do
[user.follower_address | following]
end
end
def move_following(origin, target) do
__MODULE__
|> join(:inner, [r], f in assoc(r, :follower))
|> where(following_id: ^origin.id)
|> where([r, f], f.allow_following_move == true)
|> limit(50)
|> preload([:follower])
|> Repo.all()
|> Enum.map(fn following_relationship ->
Repo.delete(following_relationship)
Pleroma.Web.CommonAPI.follow(following_relationship.follower, target)
end)
|> case do
[] -> :ok
_ -> move_following(origin, target)
end
end
end

View file

@ -251,10 +251,13 @@ defmodule Pleroma.Notification do
end
end
def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity)
when type in ["Like", "Announce", "Follow"] do
users = get_notified_from_activity(activity)
notifications = Enum.map(users, fn user -> create_notification(activity, user) end)
def create_notifications(%Activity{data: %{"type" => type}} = activity)
when type in ["Like", "Announce", "Follow", "Move"] do
notifications =
activity
|> get_notified_from_activity()
|> Enum.map(&create_notification(activity, &1))
{:ok, notifications}
end
@ -276,19 +279,15 @@ defmodule Pleroma.Notification do
def get_notified_from_activity(activity, local_only \\ true)
def get_notified_from_activity(
%Activity{data: %{"to" => _, "type" => type} = _data} = activity,
local_only
)
when type in ["Create", "Like", "Announce", "Follow"] do
recipients =
[]
|> Utils.maybe_notify_to_recipients(activity)
|> Utils.maybe_notify_mentioned_recipients(activity)
|> Utils.maybe_notify_subscribers(activity)
|> Enum.uniq()
User.get_users_from_set(recipients, local_only)
def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only)
when type in ["Create", "Like", "Announce", "Follow", "Move"] do
[]
|> Utils.maybe_notify_to_recipients(activity)
|> Utils.maybe_notify_mentioned_recipients(activity)
|> Utils.maybe_notify_subscribers(activity)
|> Utils.maybe_notify_followers(activity)
|> Enum.uniq()
|> User.get_users_from_set(local_only)
end
def get_notified_from_activity(_, _local_only), do: []

View file

@ -103,7 +103,9 @@ defmodule Pleroma.User do
field(:raw_fields, {:array, :map}, default: [])
field(:discoverable, :boolean, default: false)
field(:invisible, :boolean, default: false)
field(:allow_following_move, :boolean, default: true)
field(:skip_thread_containment, :boolean, default: false)
field(:also_known_as, {:array, :string}, default: [])
embeds_one(
:notification_settings,
@ -115,8 +117,6 @@ defmodule Pleroma.User do
has_many(:registrations, Registration)
has_many(:deliveries, Delivery)
field(:info, :map, default: %{})
timestamps()
end
@ -222,7 +222,6 @@ defmodule Pleroma.User do
params =
params
|> Map.put(:info, params[:info] || %{})
|> truncate_if_exists(:name, name_limit)
|> truncate_if_exists(:bio, bio_limit)
|> truncate_fields_param()
@ -251,7 +250,8 @@ defmodule Pleroma.User do
:fields,
:following_count,
:discoverable,
:invisible
:invisible,
:also_known_as
]
)
|> validate_required([:name, :ap_id])
@ -293,13 +293,15 @@ defmodule Pleroma.User do
:hide_followers_count,
:hide_follows_count,
:hide_favorites,
:allow_following_move,
:background,
:show_role,
:skip_thread_containment,
:fields,
:raw_fields,
:pleroma_settings_store,
:discoverable
:discoverable,
:also_known_as
]
)
|> unique_constraint(:nickname)
@ -337,9 +339,11 @@ defmodule Pleroma.User do
:hide_follows,
:fields,
:hide_followers,
:allow_following_move,
:discoverable,
:hide_followers_count,
:hide_follows_count
:hide_follows_count,
:also_known_as
]
)
|> unique_constraint(:nickname)
@ -1197,7 +1201,7 @@ defmodule Pleroma.User do
def external_users(opts \\ []) do
query =
external_users_query()
|> select([u], struct(u, [:id, :ap_id, :info]))
|> select([u], struct(u, [:id, :ap_id]))
query =
if opts[:max_id],

View file

@ -541,6 +541,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
def move(%User{} = origin, %User{} = target, local \\ true) do
params = %{
"type" => "Move",
"actor" => origin.ap_id,
"object" => origin.ap_id,
"target" => target.ap_id
}
with true <- origin.ap_id in target.also_known_as,
{:ok, activity} <- insert(params, local) do
maybe_federate(activity)
BackgroundWorker.enqueue("move_following", %{
"origin_id" => origin.id,
"target_id" => target.id
})
{:ok, activity}
else
false -> {:error, "Target account must have the origin in `alsoKnownAs`"}
err -> err
end
end
defp fetch_activities_for_context_query(context, opts) do
public = [Pleroma.Constants.as_public()]
@ -1171,7 +1195,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
name: data["name"],
follower_address: data["followers"],
following_address: data["following"],
bio: data["summary"]
bio: data["summary"],
also_known_as: Map.get(data, "alsoKnownAs", [])
}
# nickname can be nil because of virtual actors
@ -1233,13 +1258,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
defp collection_private(data) do
if is_map(data["first"]) and
data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do
defp collection_private(%{"first" => first}) do
if is_map(first) and
first["type"] in ["CollectionPage", "OrderedCollectionPage"] do
{:ok, false}
else
with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <-
Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do
Fetcher.fetch_and_contain_remote_object_from_id(first) do
{:ok, false}
else
{:error, {:ok, %{status: code}}} when code in [401, 403] ->
@ -1254,6 +1279,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
defp collection_private(_data), do: {:ok, true}
def user_data_from_user_object(data) do
with {:ok, data} <- MRF.filter(data),
{:ok, data} <- object_to_user_data(data) do

View file

@ -669,7 +669,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
update_data =
new_user_data
|> Map.take([:avatar, :banner, :bio, :name])
|> Map.take([:avatar, :banner, :bio, :name, :also_known_as])
|> Map.put(:fields, fields)
|> Map.put(:locked, locked)
|> Map.put(:invisible, invisible)
@ -857,6 +857,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
def handle_incoming(
%{
"type" => "Move",
"actor" => origin_actor,
"object" => origin_actor,
"target" => target_actor
},
_options
) do
with %User{} = origin_user <- User.get_cached_by_ap_id(origin_actor),
{:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_actor),
true <- origin_actor in target_user.also_known_as do
ActivityPub.move(origin_user, target_user, false)
else
_e -> :error
end
end
def handle_incoming(_, _), do: :error
@spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil

View file

@ -14,6 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
def is_public?(%Object{data: data}), do: is_public?(data)
def is_public?(%Activity{data: %{"type" => "Move"}}), do: true
def is_public?(%Activity{data: data}), do: is_public?(data)
def is_public?(%{"directMessage" => true}), do: false
def is_public?(data), do: Utils.label_in_message?(Pleroma.Constants.as_public(), data)

View file

@ -451,6 +451,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
recipients ++ to
end
def maybe_notify_to_recipients(recipients, _), do: recipients
def maybe_notify_mentioned_recipients(
recipients,
%Activity{data: %{"to" => _to, "type" => type} = data} = activity
@ -502,6 +504,17 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def maybe_notify_subscribers(recipients, _), do: recipients
def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = activity) do
with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do
user
|> User.get_followers()
|> Enum.map(& &1.ap_id)
|> Enum.concat(recipients)
end
end
def maybe_notify_followers(recipients, _), do: recipients
def maybe_extract_mentions(%{"tag" => tag}) do
tag
|> Enum.filter(fn x -> is_map(x) && x["type"] == "Mention" end)

View file

@ -152,6 +152,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
:hide_favorites,
:show_role,
:skip_thread_containment,
:allow_following_move,
:discoverable
]
|> Enum.reduce(%{}, fn key, acc ->

View file

@ -162,6 +162,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|> maybe_put_chat_token(user, opts[:for], opts)
|> maybe_put_activation_status(user, opts[:for])
|> maybe_put_follow_requests_count(user, opts[:for])
|> maybe_put_allow_following_move(user, opts[:for])
|> maybe_put_unread_conversation_count(user, opts[:for])
end
@ -238,6 +239,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
defp maybe_put_notification_settings(data, _, _), do: data
defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: user_id}) do
Kernel.put_in(data, [:pleroma, :allow_following_move], user.allow_following_move)
end
defp maybe_put_allow_following_move(data, _, _), do: data
defp maybe_put_activation_status(data, user, %User{is_admin: true}) do
Kernel.put_in(data, [:pleroma, :deactivated], user.deactivated)
end

View file

@ -37,32 +37,24 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
}
case mastodon_type do
"mention" ->
response
|> Map.merge(%{
status: StatusView.render("show.json", %{activity: activity, for: user})
})
"favourite" ->
response
|> Map.merge(%{
status: StatusView.render("show.json", %{activity: parent_activity, for: user})
})
"reblog" ->
response
|> Map.merge(%{
status: StatusView.render("show.json", %{activity: parent_activity, for: user})
})
"follow" ->
response
_ ->
nil
"mention" -> put_status(response, activity, user)
"favourite" -> put_status(response, parent_activity, user)
"reblog" -> put_status(response, parent_activity, user)
"move" -> put_target(response, activity, user)
"follow" -> response
_ -> nil
end
else
_ -> nil
end
end
defp put_status(response, activity, user) do
Map.put(response, :status, StatusView.render("show.json", %{activity: activity, for: user}))
end
defp put_target(response, activity, user) do
target = User.get_cached_by_ap_id(activity.data["target"])
Map.put(response, :target, AccountView.render("show.json", %{user: target, for: user}))
end
end

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Web.Push.Impl do
require Logger
import Ecto.Query
@types ["Create", "Follow", "Announce", "Like"]
@types ["Create", "Follow", "Announce", "Like", "Move"]
@doc "Performs sending notifications for user subscriptions"
@spec perform(Notification.t()) :: list(any) | :error

View file

@ -71,4 +71,11 @@ defmodule Pleroma.Workers.BackgroundWorker do
activity = Activity.get_by_id(activity_id)
Pleroma.Web.RichMedia.Helpers.perform(:fetch, activity)
end
def perform(%{"op" => "move_following", "origin_id" => origin_id, "target_id" => target_id}, _) do
origin = User.get_cached_by_id(origin_id)
target = User.get_cached_by_id(target_id)
Pleroma.FollowingRelationship.move_following(origin, target)
end
end