From c5d946bc92fa77f457b07e4fb9d113ff15cf87de Mon Sep 17 00:00:00 2001 From: tusooa Date: Sun, 26 Mar 2023 15:12:40 -0400 Subject: [PATCH] Fix emoji reactions for legacy 2-tuple formats --- lib/pleroma/object.ex | 26 +++++++++++++ lib/pleroma/web/activity_pub/utils.ex | 6 +-- .../web/mastodon_api/views/status_view.ex | 4 +- .../controllers/emoji_reaction_controller.ex | 7 +--- test/pleroma/object_test.exs | 38 +++++++++++++++++++ test/pleroma/web/activity_pub/utils_test.exs | 27 ++++++++++++- .../mastodon_api/views/status_view_test.exs | 21 ++++++++++ .../emoji_reaction_controller_test.exs | 32 ++++++++++++++++ 8 files changed, 147 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 38accae5d..aa137d250 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -425,4 +425,30 @@ def object_data_hashtags(%{"tag" => tags}) when is_list(tags) do end def object_data_hashtags(_), do: [] + + def get_emoji_reactions(object) do + reactions = object.data["reactions"] + + if is_list(reactions) or is_map(reactions) do + reactions + |> Enum.map(fn + [_emoji, users, _maybe_url] = item when is_list(users) -> + item + + [emoji, users] when is_list(users) -> + [emoji, users, nil] + + # This case is here to process the Map situation, which will happen + # only with the legacy two-value format. + {emoji, users} when is_list(users) -> + [emoji, users, nil] + + _ -> + nil + end) + |> Enum.reject(&is_nil/1) + else + [] + end + end end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 448cd1829..437220077 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -408,11 +408,7 @@ def remove_emoji_reaction_from_object( end def get_cached_emoji_reactions(object) do - if is_list(object.data["reactions"]) do - object.data["reactions"] - else - [] - end + Object.get_emoji_reactions(object) end @spec add_like_to_object(Activity.t(), Object.t()) :: diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 95efd9fd0..dea22f9c2 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -334,8 +334,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} end emoji_reactions = - object.data - |> Map.get("reactions", []) + object + |> Object.get_emoji_reactions() |> EmojiReactionController.filter_allowed_users( opts[:for], Map.get(opts, :with_muted, false) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex index e095fa04a..662cc15d6 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex @@ -28,8 +28,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do with true <- Pleroma.Config.get([:instance, :show_reactions]), %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), - %Object{data: %{"reactions" => reactions}} when is_list(reactions) <- - Object.normalize(activity, fetch: false) do + %Object{} = object <- Object.normalize(activity, fetch: false), + reactions <- Object.get_emoji_reactions(object) do reactions = reactions |> filter(params) @@ -60,9 +60,6 @@ def filter_allowed_users(reactions, user, with_muted) do reactions |> Stream.map(fn [emoji, users, url] when is_list(users) -> filter_emoji.(emoji, users, url) - {emoji, users, url} when is_list(users) -> filter_emoji.(emoji, users, url) - {emoji, users} when is_list(users) -> filter_emoji.(emoji, users, nil) - _ -> nil end) |> Stream.reject(&is_nil/1) end diff --git a/test/pleroma/object_test.exs b/test/pleroma/object_test.exs index d536e0b16..7bc5c9928 100644 --- a/test/pleroma/object_test.exs +++ b/test/pleroma/object_test.exs @@ -444,4 +444,42 @@ test "Hashtag records are created with Object record and updated on its change" Enum.sort_by(object.hashtags, & &1.name) end end + + describe "get_emoji_reactions/1" do + test "3-tuple current format" do + object = %Object{ + data: %{ + "reactions" => [ + ["x", ["https://some/user"], "https://some/emoji"] + ] + } + } + + assert Object.get_emoji_reactions(object) == object.data["reactions"] + end + + test "2-tuple legacy format" do + object = %Object{ + data: %{ + "reactions" => [ + ["x", ["https://some/user"]] + ] + } + } + + assert Object.get_emoji_reactions(object) == [["x", ["https://some/user"], nil]] + end + + test "Map format" do + object = %Object{ + data: %{ + "reactions" => %{ + "x" => ["https://some/user"] + } + } + } + + assert Object.get_emoji_reactions(object) == [["x", ["https://some/user"], nil]] + end + end end diff --git a/test/pleroma/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs index e7d1e01c4..3f93c872b 100644 --- a/test/pleroma/web/activity_pub/utils_test.exs +++ b/test/pleroma/web/activity_pub/utils_test.exs @@ -587,15 +587,38 @@ test "removes actor from announcements" do end describe "get_cached_emoji_reactions/1" do - test "returns the data or an emtpy list" do + test "returns the normalized data or an emtpy list" do object = insert(:note) assert Utils.get_cached_emoji_reactions(object) == [] object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]}) - assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]] + assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"], nil]] object = insert(:note, data: %{"reactions" => %{}}) assert Utils.get_cached_emoji_reactions(object) == [] end end + + describe "add_emoji_reaction_to_object/1" do + test "works with legacy 2-tuple format" do + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + + note = + insert(:note, + user: user, + data: %{ + "reactions" => [["😿", [other_user.ap_id]]] + } + ) + + _activity = insert(:note_activity, user: user, note: note) + + Utils.add_emoji_reaction_to_object( + %Activity{data: %{"content" => "😿", "actor" => third_user.ap_id}}, + note + ) + end + end end diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index a1f3e3e1d..b93335190 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -74,6 +74,27 @@ test "has an emoji reaction list" do ] end + test "works with legacy-formatted reactions" do + user = insert(:user) + other_user = insert(:user) + + note = + insert(:note, + user: user, + data: %{ + "reactions" => [["😿", [other_user.ap_id]]] + } + ) + + activity = insert(:note_activity, user: user, note: note) + + status = StatusView.render("show.json", activity: activity, for: user) + + assert status[:pleroma][:emoji_reactions] == [ + %{name: "😿", count: 1, me: false, url: nil, account_ids: [other_user.id]} + ] + end + test "works correctly with badly formatted emojis" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "yo"}) diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs index d81b47a6b..21e7d4839 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs @@ -245,6 +245,38 @@ test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do result end + test "GET /api/v1/pleroma/statuses/:id/reactions with legacy format", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + note = + insert(:note, + user: user, + data: %{ + "reactions" => [["😿", [other_user.ap_id]]] + } + ) + + activity = insert(:note_activity, user: user, note: note) + + result = + conn + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") + |> json_response_and_validate_schema(200) + + other_user_id = other_user.id + + assert [ + %{ + "name" => "😿", + "count" => 1, + "me" => false, + "url" => nil, + "accounts" => [%{"id" => ^other_user_id}] + } + ] = result + end + test "GET /api/v1/pleroma/statuses/:id/reactions?with_muted=true", %{conn: conn} do user = insert(:user) user2 = insert(:user)