diff options
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 22 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/side_effects.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 53 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 46 | ||||
| -rw-r--r-- | test/web/activity_pub/side_effects_test.exs | 9 | 
5 files changed, 52 insertions, 96 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3e4f3ad30..4cc9fe16c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -321,28 +321,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      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()) ::            {:ok, Activity.t()} | {:error, any()}    def follow(follower, followed, activity_id \\ nil, local \\ true, opts \\ []) do diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 09fd7d7c9..de143b8f0 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -21,13 +21,21 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do    def handle(object, meta \\ [])    # 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 -    {: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.remote_user_changeset(new_user_data) -    |> User.update_and_set_cache() +      User.get_by_ap_id(updated_object["id"]) +      |> User.remote_user_changeset(new_user_data) +      |> User.update_and_set_cache() +    end      {:ok, object, meta}    end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index c38c2b895..f0499621a 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -20,6 +20,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do    alias Pleroma.Plugs.RateLimiter    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.ActivityPub.Pipeline +  alias Pleroma.Web.ActivityPub.Builder    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.MastodonAPI.ListView    alias Pleroma.Web.MastodonAPI.MastodonAPI @@ -179,34 +181,39 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do        |> Maps.put_if_present(:default_scope, params["source"]["privacy"])        |> Maps.put_if_present(:actor_type, params[:actor_type]) -    changeset = User.update_changeset(user, user_params) - -    with {:ok, user} <- User.update_and_set_cache(changeset) do -      user -      |> build_update_activity_params() -      |> ActivityPub.update() - -      render(conn, "show.json", user: user, for: user, with_pleroma_settings: true) +    # What happens here: +    # +    # We want to update the user through the pipeline, but the ActivityPub +    # update information is not quite enough for this, because this also +    # contains local settings that don't federate and don't even appear +    # in the Update activity.  +    #  +    # 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        _e -> render_error(conn, :forbidden, "Invalid request")      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      if Enum.all?(fields, &is_tuple/1) do        Enum.map(fields, fn {_, v} -> v end) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 7693f6400..ce35c9605 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1092,52 +1092,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      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      setup do        reporter = insert(:user) diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs index 1d7c2736b..12c9ef1da 100644 --- a/test/web/activity_pub/side_effects_test.exs +++ b/test/web/activity_pub/side_effects_test.exs @@ -78,6 +78,15 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do        user = User.get_by_id(user.id)        assert user.name == "new name!"      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    describe "delete objects" do  | 
