X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fmastodon_api%2Fcontrollers%2Fstatus_controller.ex;h=9e3a584f0b03e761be36cd716fa2b84010934a58;hb=c3fde9577d5822243a7567a55cefa2fd2f289559;hp=da14c0b6c33a6965b9b2187bee37eafd12e15bf4;hpb=8f5589cf667d8dd24da07e58db94225d81a55a7b;p=akkoma diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index da14c0b6c..41fbd7acf 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors +# Copyright © 2017-2021 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.StatusController do @@ -13,9 +13,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do alias Pleroma.Activity alias Pleroma.Bookmark alias Pleroma.Object - alias Pleroma.Plugs.OAuthScopesPlug - alias Pleroma.Plugs.RateLimiter alias Pleroma.Repo + alias Pleroma.Config alias Pleroma.ScheduledActivity alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -23,11 +22,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.ScheduledActivityView + alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.Plugs.OAuthScopesPlug + alias Pleroma.Web.Plugs.RateLimiter plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(:skip_plug, Pleroma.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, @@ -35,8 +39,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do when action in [ :index, :show, - :card, - :context + :context, + :translate ] ) @@ -105,7 +109,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do `ids` query param is required """ - def index(%{assigns: %{user: user}} = conn, %{ids: ids} = _params) do + def index(%{assigns: %{user: user}} = conn, %{ids: ids} = params) do limit = 100 activities = @@ -117,15 +121,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do render(conn, "index.json", activities: activities, for: user, - as: :activity + as: :activity, + with_muted: Map.get(params, :with_muted, false) ) end @doc """ POST /api/v1/statuses - - Creates a scheduled status when `scheduled_at` param is present and it's far enough """ + # Creates a scheduled status when `scheduled_at` param is present and it's far enough def create( %{ assigns: %{user: user}, @@ -134,7 +138,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do _ ) when not is_nil(scheduled_at) do - params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id]) + params = + Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id]) + |> put_application(conn) attrs = %{ params: Map.new(params, fn {key, value} -> {to_string(key), value} end), @@ -156,13 +162,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do end end - @doc """ - POST /api/v1/statuses - - Creates a regular status - """ + # Creates a regular status def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, _) do - params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id]) + params = + Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id]) + |> put_application(conn) with {:ok, activity} <- CommonAPI.post(user, params) do try_render(conn, "show.json", @@ -190,13 +194,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do end @doc "GET /api/v1/statuses/:id" - def show(%{assigns: %{user: user}} = conn, %{id: id}) do + def show(%{assigns: %{user: user}} = conn, %{id: id} = params) do with %Activity{} = activity <- Activity.get_by_id_with_object(id), true <- Visibility.visible_for_user?(activity, user) do try_render(conn, "show.json", activity: activity, for: user, - with_direct_conversation_id: true + with_direct_conversation_id: true, + with_muted: Map.get(params, :with_muted, false) ) else _ -> {:error, :not_found} @@ -254,6 +259,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do def pin(%{assigns: %{user: user}} = conn, %{id: ap_id_or_id}) do with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do try_render(conn, "show.json", activity: activity, for: user, as: :activity) + else + {:error, :pinned_statuses_limit_reached} -> + {:error, "You have already pinned the maximum number of statuses"} + + {:error, :ownership_error} -> + {:error, :unprocessable_entity, "Someone else's status cannot be pinned"} + + {:error, :visibility_error} -> + {:error, :unprocessable_entity, "Non-public status cannot be pinned"} + + error -> + error end end @@ -300,24 +317,12 @@ 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]), %Activity{} = activity <- Activity.get_by_id_with_object(id), {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, - %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do + %Object{data: %{"likes" => likes}} <- Object.normalize(activity, fetch: false) do users = User |> Ecto.Query.where([u], u.ap_id in ^likes) @@ -338,7 +343,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do with %Activity{} = activity <- Activity.get_by_id_with_object(id), {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, %Object{data: %{"announcements" => announces, "id" => ap_id}} <- - Object.normalize(activity) do + Object.normalize(activity, fetch: false) do announces = "Announce" |> Activity.Queries.by_type() @@ -369,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 @@ -413,4 +420,60 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do as: :activity ) 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 + Map.put(params, :generator, %{type: "Application", name: client_name, url: website}) + else + Map.put(params, :generator, nil) + end + end + + defp put_application(params, _), do: Map.put(params, :generator, nil) end