Allow reacting with remote emoji when they exist on the post (#200)
[akkoma] / lib / pleroma / web / pleroma_api / controllers / emoji_reaction_controller.ex
index a002912f33be2d7da1831bd510cb427c2273cab7..0933363a688171756aff96d4cceb35fdfaddf651 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
@@ -7,9 +7,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
 
   alias Pleroma.Activity
   alias Pleroma.Object
-  alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.User
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.MastodonAPI.StatusView
+  alias Pleroma.Web.Plugs.OAuthScopesPlug
 
   plug(Pleroma.Web.ApiSpec.CastAndValidate)
   plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action in [:create, :delete])
@@ -22,24 +23,62 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
 
   defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.EmojiReactionOperation
 
+  action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+
   def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
-    with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
+    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) do
-      reactions = filter(reactions, params)
+           Object.normalize(activity, fetch: false) do
+      reactions =
+        reactions
+        |> filter(params)
+        |> filter_allowed_users(user, Map.get(params, :with_muted, false))
+
       render(conn, "index.json", emoji_reactions: reactions, user: user)
     else
       _e -> json(conn, [])
     end
   end
 
+  def filter_allowed_users(reactions, user, with_muted) do
+    exclude_ap_ids =
+      if is_nil(user) do
+        []
+      else
+        User.cached_blocked_users_ap_ids(user) ++
+          if not with_muted, do: User.cached_muted_users_ap_ids(user), else: []
+      end
+
+    filter_emoji = fn emoji, users, url ->
+      case Enum.reject(users, &(&1 in exclude_ap_ids)) do
+        [] -> nil
+        users -> {emoji, users, url}
+      end
+    end
+
+    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
+
   defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
-    Enum.filter(reactions, fn [e, _] -> e == emoji end)
+    Enum.filter(reactions, fn [e, _, _] -> e == emoji end)
   end
 
   defp filter(reactions, _), do: reactions
 
   def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+    emoji =
+      emoji
+      |> Pleroma.Emoji.fully_qualify_emoji()
+      |> Pleroma.Emoji.maybe_quote()
+
     with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
       activity = Activity.get_by_id(activity_id)
 
@@ -50,6 +89,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
   end
 
   def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+    emoji =
+      emoji
+      |> Pleroma.Emoji.fully_qualify_emoji()
+      |> Pleroma.Emoji.maybe_quote()
+
     with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
       activity = Activity.get_by_id(activity_id)