From e88f36f72b5317debafcc4209b91eb35ad8f0691 Mon Sep 17 00:00:00 2001
From: =?utf8?q?H=C3=A9l=C3=A8ne?= <pleroma-dev@helene.moe>
Date: Sun, 11 Sep 2022 04:54:04 +0200
Subject: [PATCH] ObjectView: do not fetch an object for its ID

Non-Create/Listen activities had their associated object field
normalized and fetched, but only to use their `id` field, which is both
slow and redundant. This also failed on Undo activities, which delete
the associated object/activity in database.

Undo activities will now render properly and database loads should
improve ever so slightly.
---
 lib/pleroma/object.ex                             | 15 ++++++++++-----
 lib/pleroma/web/activity_pub/views/object_view.ex |  4 ++--
 .../web/activity_pub/views/object_view_test.exs   | 14 ++++++++++++++
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 00af77f57..a75d85c47 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -145,7 +145,7 @@ defmodule Pleroma.Object do
     Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}")
   end
 
-  def normalize(_, options \\ [fetch: false])
+  def normalize(_, options \\ [fetch: false, id_only: false])
 
   # If we pass an Activity to Object.normalize(), we can try to use the preloaded object.
   # Use this whenever possible, especially when walking graphs in an O(N) loop!
@@ -173,10 +173,15 @@ defmodule Pleroma.Object do
   def normalize(%{"id" => ap_id}, options), do: normalize(ap_id, options)
 
   def normalize(ap_id, options) when is_binary(ap_id) do
-    if Keyword.get(options, :fetch) do
-      Fetcher.fetch_object_from_id!(ap_id, options)
-    else
-      get_cached_by_ap_id(ap_id)
+    cond do
+      Keyword.get(options, :id_only) ->
+        ap_id
+
+      Keyword.get(options, :fetch) ->
+        Fetcher.fetch_object_from_id!(ap_id, options)
+
+      true ->
+        get_cached_by_ap_id(ap_id)
     end
   end
 
diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex
index d9b59406c..29e2bbc81 100644
--- a/lib/pleroma/web/activity_pub/views/object_view.ex
+++ b/lib/pleroma/web/activity_pub/views/object_view.ex
@@ -29,11 +29,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
 
   def render("object.json", %{object: %Activity{} = activity}) do
     base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
-    object = Object.normalize(activity, fetch: false)
+    object_id = Object.normalize(activity, id_only: true)
 
     additional =
       Transmogrifier.prepare_object(activity.data)
-      |> Map.put("object", object.data["id"])
+      |> Map.put("object", object_id)
 
     Map.merge(base, additional)
   end
diff --git a/test/pleroma/web/activity_pub/views/object_view_test.exs b/test/pleroma/web/activity_pub/views/object_view_test.exs
index 923515dec..9348c09be 100644
--- a/test/pleroma/web/activity_pub/views/object_view_test.exs
+++ b/test/pleroma/web/activity_pub/views/object_view_test.exs
@@ -81,4 +81,18 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
     assert result["object"] == object.data["id"]
     assert result["type"] == "Announce"
   end
+
+  test "renders an undo announce activity" do
+    note = insert(:note_activity)
+    user = insert(:user)
+
+    {:ok, announce} = CommonAPI.repeat(note.id, user)
+    {:ok, undo} = CommonAPI.unrepeat(note.id, user)
+
+    result = ObjectView.render("object.json", %{object: undo})
+
+    assert result["id"] == undo.data["id"]
+    assert result["object"] == announce.data["id"]
+    assert result["type"] == "Undo"
+  end
 end
-- 
2.49.0