Allow listing languages, setting source language (#192)
[akkoma] / lib / pleroma / web / mastodon_api / controllers / status_controller.ex
index 724dc5c5d9e7cf720466f19ff8d420636aed5eea..41fbd7acf2f910e8a8ec47a01e7bec9af70e7a37 100644 (file)
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
   alias Pleroma.Bookmark
   alias Pleroma.Object
   alias Pleroma.Repo
+  alias Pleroma.Config
   alias Pleroma.ScheduledActivity
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
@@ -27,12 +28,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
 
   plug(Pleroma.Web.ApiSpec.CastAndValidate)
 
-  plug(
-    :skip_plug,
-    Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug when action in [:index, :show]
-  )
+  plug(:skip_public_check when action in [:index, :show])
 
   @unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []}
+  @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
 
   plug(
     OAuthScopesPlug,
@@ -40,8 +39,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
     when action in [
            :index,
            :show,
-           :card,
-           :context
+           :context,
+           :translate
          ]
   )
 
@@ -318,18 +317,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
     end
   end
 
-  @doc "GET /api/v1/statuses/:id/card"
-  @deprecated "https://github.com/tootsuite/mastodon/pull/11213"
-  def card(%{assigns: %{user: user}} = conn, %{id: status_id}) do
-    with %Activity{} = activity <- Activity.get_by_id(status_id),
-         true <- Visibility.visible_for_user?(activity, user) do
-      data = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
-      render(conn, "card.json", data)
-    else
-      _ -> render_error(conn, :not_found, "Record not found")
-    end
-  end
-
   @doc "GET /api/v1/statuses/:id/favourited_by"
   def favourited_by(%{assigns: %{user: user}} = conn, %{id: id}) do
     with true <- Pleroma.Config.get([:instance, :show_reactions]),
@@ -387,11 +374,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
   def context(%{assigns: %{user: user}} = conn, %{id: id}) do
     with %Activity{} = activity <- Activity.get_by_id(id) do
       activities =
-        ActivityPub.fetch_activities_for_context(activity.data["context"], %{
+        activity.data["context"]
+        |> ActivityPub.fetch_activities_for_context(%{
           blocking_user: user,
           user: user,
           exclude_id: activity.id
         })
+        |> Enum.filter(fn activity -> Visibility.visible_for_user?(activity, user) end)
 
       render(conn, "context.json", activity: activity, activities: activities, user: user)
     end
@@ -432,6 +421,51 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
     )
   end
 
+  @doc "GET /api/v1/statuses/:id/translations/:language"
+  def translate(%{assigns: %{user: user}} = conn, %{id: id, language: language} = params) do
+    with {:enabled, true} <- {:enabled, Config.get([:translator, :enabled])},
+         %Activity{} = activity <- Activity.get_by_id_with_object(id),
+         {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
+         translation_module <- Config.get([:translator, :module]),
+         {:ok, detected, translation} <-
+           fetch_or_translate(
+             activity.id,
+             activity.object.data["content"],
+             Map.get(params, :from, nil),
+             language,
+             translation_module
+           ) do
+      json(conn, %{detected_language: detected, text: translation})
+    else
+      {:enabled, false} ->
+        conn
+        |> put_status(:bad_request)
+        |> json(%{"error" => "Translation is not enabled"})
+
+      {:visible, false} ->
+        {:error, :not_found}
+
+      e ->
+        e
+    end
+  end
+
+  defp fetch_or_translate(status_id, text, source_language, target_language, translation_module) do
+    @cachex.fetch!(
+      :translations_cache,
+      "translations:#{status_id}:#{source_language}:#{target_language}",
+      fn _ ->
+        value = translation_module.translate(text, source_language, target_language)
+
+        with {:ok, _, _} <- value do
+          value
+        else
+          _ -> {:ignore, value}
+        end
+      end
+    )
+  end
+
   defp put_application(params, %{assigns: %{token: %Token{user: %User{} = user} = token}} = _conn) do
     if user.disclose_client do
       %{client_name: client_name, website: website} = Repo.preload(token, :app).app