Emoji reactions: Change cache and reply format
authorlain <lain@soykaf.club>
Wed, 22 Jan 2020 12:57:42 +0000 (13:57 +0100)
committerlain <lain@soykaf.club>
Wed, 22 Jan 2020 12:57:42 +0000 (13:57 +0100)
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
test/web/activity_pub/activity_pub_test.exs
test/web/mastodon_api/views/status_view_test.exs
test/web/pleroma_api/controllers/pleroma_api_controller_test.exs

index db70842461c29f5376b56db5337affc2d54c24e8..4def431f152518fdcb0f0d6880f1db42dce5742b 100644 (file)
@@ -312,19 +312,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do
     |> Map.put("content", emoji)
   end
 
-  @spec update_element_in_object(String.t(), list(any), Object.t()) ::
+  @spec update_element_in_object(String.t(), list(any), Object.t(), integer() | nil) ::
           {:ok, Object.t()} | {:error, Ecto.Changeset.t()}
-  def update_element_in_object(property, element, object) do
+  def update_element_in_object(property, element, object, count \\ nil) do
     length =
-      if is_map(element) do
-        element
-        |> Map.values()
-        |> List.flatten()
-        |> length()
-      else
-        element
-        |> length()
-      end
+      count ||
+        length(element)
 
     data =
       Map.merge(
@@ -344,29 +337,52 @@ defmodule Pleroma.Web.ActivityPub.Utils do
         %Activity{data: %{"content" => emoji, "actor" => actor}},
         object
       ) do
-    reactions = object.data["reactions"] || %{}
-    emoji_actors = reactions[emoji] || []
-    new_emoji_actors = [actor | emoji_actors] |> Enum.uniq()
-    new_reactions = Map.put(reactions, emoji, new_emoji_actors)
-    update_element_in_object("reaction", new_reactions, object)
+    reactions = object.data["reactions"] || []
+
+    new_reactions =
+      case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+        nil ->
+          reactions ++ [[emoji, [actor]]]
+
+        index ->
+          List.update_at(
+            reactions,
+            index,
+            fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
+          )
+      end
+
+    count = emoji_count(new_reactions)
+
+    update_element_in_object("reaction", new_reactions, object, count)
+  end
+
+  def emoji_count(reactions_list) do
+    Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
   end
 
   def remove_emoji_reaction_from_object(
         %Activity{data: %{"content" => emoji, "actor" => actor}},
         object
       ) do
-    reactions = object.data["reactions"] || %{}
-    emoji_actors = reactions[emoji] || []
-    new_emoji_actors = List.delete(emoji_actors, actor)
+    reactions = object.data["reactions"] || []
 
     new_reactions =
-      if new_emoji_actors == [] do
-        Map.delete(reactions, emoji)
-      else
-        Map.put(reactions, emoji, new_emoji_actors)
+      case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+        nil ->
+          reactions
+
+        index ->
+          List.update_at(
+            reactions,
+            index,
+            fn [emoji, users] -> [emoji, List.delete(users, actor)] end
+          )
+          |> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
       end
 
-    update_element_in_object("reaction", new_reactions, object)
+    count = emoji_count(new_reactions)
+    update_element_in_object("reaction", new_reactions, object, count)
   end
 
   @spec add_like_to_object(Activity.t(), Object.t()) ::
index b59ac39bc4908f6d7453b6d2fb1c70976d759ee9..64a97896aab9f985de0017d9268424c7453e7ec0 100644 (file)
@@ -255,12 +255,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
 
     emoji_reactions =
       with %{data: %{"reactions" => emoji_reactions}} <- object do
-        Enum.map(emoji_reactions, fn {emoji, users} ->
-          {emoji, length(users)}
+        Enum.map(emoji_reactions, fn [emoji, users] ->
+          [emoji, length(users)]
         end)
-        |> Enum.into(%{})
       else
-        _ -> %{}
+        _ -> []
       end
 
     %{
index 3285dc11b7a4e238125e7503eea94806ee55e9f0..bb19836ae18ecf051156847fafba52a932b7b4e4 100644 (file)
@@ -43,21 +43,21 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
 
   def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
     with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
-         %Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do
+         %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
+           Object.normalize(activity) do
       reactions =
         emoji_reactions
-        |> Enum.map(fn {emoji, users} ->
+        |> Enum.map(fn [emoji, users] ->
           users = Enum.map(users, &User.get_cached_by_ap_id/1)
           {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})}
         end)
-        |> Enum.into(%{})
 
       conn
       |> json(reactions)
     else
       _e ->
         conn
-        |> json(%{})
+        |> json([])
     end
   end
 
index ad6b9810cf71e0fe9ec4d81871b53a11c48db14f..ff4604a524303e676b671372862497378bad4c5d 100644 (file)
@@ -867,6 +867,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     test "adds an emoji reaction activity to the db" do
       user = insert(:user)
       reactor = insert(:user)
+      third_user = insert(:user)
+      fourth_user = insert(:user)
       {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
       assert object = Object.normalize(activity)
 
@@ -881,7 +883,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]]
       assert reaction_activity.data["context"] == object.data["context"]
       assert object.data["reaction_count"] == 1
-      assert object.data["reactions"]["🔥"] == [reactor.ap_id]
+      assert object.data["reactions"] == [["🔥", [reactor.ap_id]]]
+
+      {:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(third_user, object, "☕")
+
+      assert object.data["reaction_count"] == 2
+      assert object.data["reactions"] == [["🔥", [reactor.ap_id]], ["☕", [third_user.ap_id]]]
+
+      {:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(fourth_user, object, "🔥")
+
+      assert object.data["reaction_count"] == 3
+
+      assert object.data["reactions"] == [
+               ["🔥", [fourth_user.ap_id, reactor.ap_id]],
+               ["☕", [third_user.ap_id]]
+             ]
     end
   end
 
@@ -919,7 +935,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       object = Object.get_by_ap_id(object.data["id"])
       assert object.data["reaction_count"] == 0
-      assert object.data["reactions"] == %{}
+      assert object.data["reactions"] == []
     end
   end
 
index b54b19c0b3d1929a082ea9781ef86be5306a0461..069bb8eac2b713baa4a87c2e0f3d5e36b3631a14 100644 (file)
@@ -31,13 +31,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
     {:ok, activity} = CommonAPI.post(user, %{"status" => "dae cofe??"})
 
     {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, user, "☕")
-    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
     {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵")
+    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
     activity = Repo.get(Activity, activity.id)
     status = StatusView.render("show.json", activity: activity)
 
-    assert status[:pleroma][:emoji_reactions]["🍵"] == 1
-    assert status[:pleroma][:emoji_reactions]["☕"] == 2
+    assert status[:pleroma][:emoji_reactions] == [["☕", 2], ["🍵", 1]]
   end
 
   test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
@@ -189,7 +188,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
         expires_at: nil,
         direct_conversation_id: nil,
         thread_muted: false,
-        emoji_reactions: %{}
+        emoji_reactions: []
       }
     }
 
index fb75001348ab62306bba4b4fd2ef1aac20c52059..a79ecd05b1fa85a12069bcbfcb2391236c91fe78 100644 (file)
@@ -62,7 +62,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do
       |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
       |> json_response(200)
 
-    assert result == %{}
+    assert result == []
 
     {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
 
@@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do
       |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
       |> json_response(200)
 
-    [represented_user] = result["🎅"]
+    [["🎅", [represented_user]]] = result
     assert represented_user["id"] == other_user.id
   end