don't persist undo of follows (#149)
authorfloatingghost <hannah@coffee-and-dreams.uk>
Fri, 5 Aug 2022 13:28:56 +0000 (13:28 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Fri, 5 Aug 2022 13:28:56 +0000 (13:28 +0000)
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/149

lib/pleroma/web/activity_pub/activity_pub.ex
priv/repo/migrations/20220805123645_remove_remote_cancelled_follow_requests.exs [new file with mode: 0644]
test/pleroma/web/activity_pub/activity_pub_test.exs

index 8ab87bfee8742e9030573af86fc2bd1277dcd23a..03e72be58443f9f7e3822cc23a1d84499ac7d7d4 100644 (file)
@@ -327,7 +327,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
-  defp do_unfollow(follower, followed, activity_id, local) do
+  defp do_unfollow(follower, followed, activity_id, local)
+
+  defp do_unfollow(follower, followed, activity_id, local) when local == true do
     with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
          {:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
          unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
@@ -341,6 +343,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
+  defp do_unfollow(follower, followed, activity_id, false) do
+    # On a remote unfollow, _remove_ their activity from the database, since some software (MISSKEEEEY)
+    # uses deterministic ids for follows.
+    with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
+         {:ok, _activity} <- Repo.delete(follow_activity),
+         unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
+         unfollow_activity <- remote_unfollow_data(unfollow_data),
+         _ <- notify_and_stream(unfollow_activity) do
+      {:ok, unfollow_activity}
+    else
+      nil -> nil
+      {:error, error} -> Repo.rollback(error)
+    end
+  end
+
+  defp remote_unfollow_data(data) do
+    {recipients, _, _} = get_recipients(data)
+
+    %Activity{
+      data: data,
+      local: false,
+      actor: data["actor"],
+      recipients: recipients
+    }
+  end
+
   @spec flag(map()) :: {:ok, Activity.t()} | {:error, any()}
   def flag(params) do
     with {:ok, result} <- Repo.transaction(fn -> do_flag(params) end) do
diff --git a/priv/repo/migrations/20220805123645_remove_remote_cancelled_follow_requests.exs b/priv/repo/migrations/20220805123645_remove_remote_cancelled_follow_requests.exs
new file mode 100644 (file)
index 0000000..3159843
--- /dev/null
@@ -0,0 +1,35 @@
+defmodule Pleroma.Repo.Migrations.RemoveRemoteCancelledFollowRequests do
+  use Ecto.Migration
+
+  def up do
+    statement = """
+    DELETE FROM
+        activities
+    WHERE
+        (data->>'type') = 'Follow'
+    AND
+        (data->>'state') = 'cancelled'
+    AND
+        local = false;
+    """
+
+    execute(statement)
+
+    statement = """
+    DELETE FROM
+        activities
+    WHERE
+        (data->>'type') = 'Undo'
+    AND
+        (data->'object'->>'type') = 'Follow'
+    AND
+        local = false;
+    """
+
+    execute(statement)
+  end
+
+  def down do
+    :ok
+  end
+end
index e6cc20bbaddaa6257d419b71c9a50341144716ce..90680e8cca8175d69bbd60aed8c0a9016ba6c047 100644 (file)
@@ -1375,6 +1375,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert embedded_object["object"] == followed.ap_id
       assert embedded_object["id"] == follow_activity.data["id"]
     end
+
+    test "it removes the follow activity if it was remote" do
+      follower = insert(:user, local: false)
+      followed = insert(:user)
+
+      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
+      {:ok, activity} = ActivityPub.unfollow(follower, followed, nil, false)
+
+      assert activity.data["type"] == "Undo"
+      assert activity.data["actor"] == follower.ap_id
+
+      activity = Activity.get_by_id(follow_activity.id)
+      assert is_nil(activity)
+      assert is_nil(Utils.fetch_latest_follow(follower, followed))
+    end
   end
 
   describe "timeline post-processing" do