ActivityPub: Remove `update` and switch to pipeline.

This commit is contained in:
lain 2020-06-22 13:59:45 +02:00
parent 1e7ca24430
commit e785cd5cae
5 changed files with 52 additions and 96 deletions

View File

@ -321,28 +321,6 @@ defp accept_or_reject(type, %{to: to, actor: actor, object: object} = params) do
end end
end end
@spec update(map()) :: {:ok, Activity.t()} | {:error, any()}
def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
local = !(params[:local] == false)
activity_id = params[:activity_id]
data =
%{
"to" => to,
"cc" => cc,
"type" => "Update",
"actor" => actor,
"object" => object
}
|> Maps.put_if_present("id", activity_id)
with {:ok, activity} <- insert(data, local),
_ <- notify_and_stream(activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@spec follow(User.t(), User.t(), String.t() | nil, boolean(), keyword()) :: @spec follow(User.t(), User.t(), String.t() | nil, boolean(), keyword()) ::
{:ok, Activity.t()} | {:error, any()} {:ok, Activity.t()} | {:error, any()}
def follow(follower, followed, activity_id \\ nil, local \\ true, opts \\ []) do def follow(follower, followed, activity_id \\ nil, local \\ true, opts \\ []) do

View File

@ -21,13 +21,21 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
def handle(object, meta \\ []) def handle(object, meta \\ [])
# Tasks this handles: # Tasks this handles:
# Update the user # - Update the user
#
# For a local user, we also get a changeset with the full information, so we
# can update non-federating, non-activitypub settings as well.
def handle(%{data: %{"type" => "Update", "object" => updated_object}} = object, meta) do def handle(%{data: %{"type" => "Update", "object" => updated_object}} = object, meta) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(updated_object) if changeset = Keyword.get(meta, :user_update_changeset) do
changeset
|> User.update_and_set_cache()
else
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(updated_object)
User.get_by_ap_id(updated_object["id"]) User.get_by_ap_id(updated_object["id"])
|> User.remote_user_changeset(new_user_data) |> User.remote_user_changeset(new_user_data)
|> User.update_and_set_cache() |> User.update_and_set_cache()
end
{:ok, object, meta} {:ok, object, meta}
end end

View File

@ -20,6 +20,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
alias Pleroma.Plugs.RateLimiter alias Pleroma.Plugs.RateLimiter
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.ListView
alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonAPI
@ -179,34 +181,39 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|> Maps.put_if_present(:default_scope, params["source"]["privacy"]) |> Maps.put_if_present(:default_scope, params["source"]["privacy"])
|> Maps.put_if_present(:actor_type, params[:actor_type]) |> Maps.put_if_present(:actor_type, params[:actor_type])
changeset = User.update_changeset(user, user_params) # What happens here:
#
with {:ok, user} <- User.update_and_set_cache(changeset) do # We want to update the user through the pipeline, but the ActivityPub
user # update information is not quite enough for this, because this also
|> build_update_activity_params() # contains local settings that don't federate and don't even appear
|> ActivityPub.update() # in the Update activity.
#
render(conn, "show.json", user: user, for: user, with_pleroma_settings: true) # So we first build the normal local changeset, then apply it to the
# user data, but don't persist it. With this, we generate the object
# data for our update activity. We feed this and the changeset as meta
# inforation into the pipeline, where they will be properly updated and
# federated.
with changeset <- User.update_changeset(user, user_params),
{:ok, unpersisted_user} <- Ecto.Changeset.apply_action(changeset, :update),
updated_object <-
Pleroma.Web.ActivityPub.UserView.render("user.json", user: user)
|> Map.delete("@context"),
{:ok, update_data, []} <- Builder.update(user, updated_object),
{:ok, _update, _} <-
Pipeline.common_pipeline(update_data,
local: true,
user_update_changeset: changeset
) do
render(conn, "show.json",
user: unpersisted_user,
for: unpersisted_user,
with_pleroma_settings: true
)
else else
_e -> render_error(conn, :forbidden, "Invalid request") _e -> render_error(conn, :forbidden, "Invalid request")
end end
end end
# Hotfix, handling will be redone with the pipeline
defp build_update_activity_params(user) do
object =
Pleroma.Web.ActivityPub.UserView.render("user.json", user: user)
|> Map.delete("@context")
%{
local: true,
to: [user.follower_address],
cc: [],
object: object,
actor: user.ap_id
}
end
defp normalize_fields_attributes(fields) do defp normalize_fields_attributes(fields) do
if Enum.all?(fields, &is_tuple/1) do if Enum.all?(fields, &is_tuple/1) do
Enum.map(fields, fn {_, v} -> v end) Enum.map(fields, fn {_, v} -> v end)

View File

@ -1092,52 +1092,6 @@ test "it filters broken threads" do
end end
end end
describe "update" do
setup do: clear_config([:instance, :max_pinned_statuses])
test "it creates an update activity with the new user data" do
user = insert(:user)
{:ok, user} = User.ensure_keys_present(user)
user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
{:ok, update} =
ActivityPub.update(%{
actor: user_data["id"],
to: [user.follower_address],
cc: [],
object: user_data
})
assert update.data["actor"] == user.ap_id
assert update.data["to"] == [user.follower_address]
assert embedded_object = update.data["object"]
assert embedded_object["id"] == user_data["id"]
assert embedded_object["type"] == user_data["type"]
end
end
test "returned pinned statuses" do
Config.put([:instance, :max_pinned_statuses], 3)
user = insert(:user)
{:ok, activity_one} = CommonAPI.post(user, %{status: "HI!!!"})
{:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
{:ok, activity_three} = CommonAPI.post(user, %{status: "HI!!!"})
CommonAPI.pin(activity_one.id, user)
user = refresh_record(user)
CommonAPI.pin(activity_two.id, user)
user = refresh_record(user)
CommonAPI.pin(activity_three.id, user)
user = refresh_record(user)
activities = ActivityPub.fetch_user_activities(user, nil, %{pinned: true})
assert 3 = length(activities)
end
describe "flag/1" do describe "flag/1" do
setup do setup do
reporter = insert(:user) reporter = insert(:user)

View File

@ -78,6 +78,15 @@ test "it updates the user", %{user: user, update: update} do
user = User.get_by_id(user.id) user = User.get_by_id(user.id)
assert user.name == "new name!" assert user.name == "new name!"
end end
test "it uses a given changeset to update", %{user: user, update: update} do
changeset = Ecto.Changeset.change(user, %{default_scope: "direct"})
assert user.default_scope == "public"
{:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset)
user = User.get_by_id(user.id)
assert user.default_scope == "direct"
end
end end
describe "delete objects" do describe "delete objects" do