ActivityPub: Remove update
and switch to pipeline.
This commit is contained in:
parent
1e7ca24430
commit
e785cd5cae
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue