From 8d1617f4392574580d0cee76c5843c9c59885570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 27 May 2022 11:27:48 +0200 Subject: [PATCH] Add a route for status quotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/web/activity_pub/activity_pub.ex | 14 +++++ .../object_validators/common_fields.ex | 2 +- .../operations/pleroma_status_operation.ex | 45 ++++++++++++++ lib/pleroma/web/api_spec/schemas/status.ex | 4 +- .../web/mastodon_api/views/status_view.ex | 2 +- .../controllers/status_controller.ex | 61 +++++++++++++++++++ lib/pleroma/web/router.ex | 2 + 7 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex create mode 100644 lib/pleroma/web/pleroma_api/controllers/status_controller.ex diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 05bd5293b6..3add644c19 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1215,6 +1215,16 @@ defp restrict_filtered(query, %{blocking_user: %User{} = user}) do defp restrict_filtered(query, _), do: query + defp restrict_quote_url(query, %{quote_url: quote_url}) do + IO.inspect(quote_url) + + from([_activity, object] in query, + where: fragment("(?)->'quoteUrl' = ?", object.data, ^quote_url) + ) + end + + defp restrict_quote_url(query, _), do: query + defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query defp exclude_poll_votes(query, _) do @@ -1378,6 +1388,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_instance(opts) |> restrict_announce_object_actor(opts) |> restrict_filtered(opts) + |> restrict_quote_url(opts) |> Activity.restrict_deactivated_users() |> exclude_poll_votes(opts) |> exclude_chat_messages(opts) @@ -1794,4 +1805,7 @@ def fetch_direct_messages_query do |> restrict_visibility(%{visibility: "direct"}) |> order_by([activity], asc: activity.id) end + + def fetch_quotes(%Activity{data: %{"id" => ap_id}} = activity, params) do + end end diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 230f90a581..cb5851f201 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -58,7 +58,7 @@ defmacro status_object_fields do field(:replies_count, :integer, default: 0) field(:like_count, :integer, default: 0) field(:announcement_count, :integer, default: 0) - field(:quote_count, :integer, default: 0) + field(:quotes_count, :integer, default: 0) field(:inReplyTo, ObjectValidators.ObjectID) field(:quoteUrl, ObjectValidators.ObjectID) field(:url, ObjectValidators.Uri) diff --git a/lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex new file mode 100644 index 0000000000..54eb57ce3b --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaStatusOperation do + alias OpenApiSpex.Operation + alias Pleroma.Web.ApiSpec.StatusOperation + alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.FlakeID + + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def quotes_operation do + %Operation{ + tags: ["Retrieve status information"], + summary: "Quoted by", + description: "View quotes for a given status", + operationId: "PleromaAPI.StatusController.quotes", + parameters: [id_param() | pagination_params()], + security: [%{"oAuth" => ["read:statuses"]}], + responses: %{ + 200 => + Operation.response( + "Array of Status", + "application/json", + StatusOperation.array_of_statuses() + ), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def id_param do + Operation.parameter(:id, :path, FlakeID, "Status ID", + example: "9umDrYheeY451cQnEe", + required: true + ) + end +end diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex index 5189cc15d7..604ed9cbe7 100644 --- a/lib/pleroma/web/api_spec/schemas/status.ex +++ b/lib/pleroma/web/api_spec/schemas/status.ex @@ -192,7 +192,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do type: :boolean, description: "`true` if the quoted post is visible to the user" }, - quote_count: %Schema{ + quotes_count: %Schema{ type: :integer, description: "How many statuses quoted this status" }, @@ -351,7 +351,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do "local" => true, "spoiler_text" => %{"text/plain" => ""}, "thread_muted" => false, - "quote_count" => 0 + "quotes_count" => 0 }, "poll" => nil, "reblog" => nil, diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index a7538380f2..71b29bb3c7 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -417,7 +417,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} parent_visible: visible_for_user?(reply_to, opts[:for]), pinned_at: pinned_at, content_type: opts[:with_source] && (object.data["content_type"] || "text/plain"), - quote_count: object.data["quotesCount"] || 0, + quotes_count: object.data["quotesCount"] || 0 } } end diff --git a/lib/pleroma/web/pleroma_api/controllers/status_controller.ex b/lib/pleroma/web/pleroma_api/controllers/status_controller.ex new file mode 100644 index 0000000000..f5906b94b8 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/status_controller.ex @@ -0,0 +1,61 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.StatusController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2] + + require Ecto.Query + require Pleroma.Constants + + alias Pleroma.Activity + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.Plugs.OAuthScopesPlug + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + plug( + OAuthScopesPlug, + %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated} when action == :quotes + ) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaStatusOperation + + @doc "GET /api/v1/pleroma/statuses/:id/quotes" + def quotes(%{assigns: %{user: user}} = conn, %{id: id} = params) do + with %Activity{object: object} <- Activity.get_by_id_with_object(id) do + params = + params + |> Map.put(:type, "Create") + |> Map.put(:blocking_user, user) + |> Map.put(:quote_url, object.data["id"]) + + recipients = + if user do + [Pleroma.Constants.as_public()] ++ [user.ap_id | User.following(user)] + else + [Pleroma.Constants.as_public()] + end + + activities = + recipients + |> ActivityPub.fetch_activities(params) + |> Enum.reverse() + + conn + |> add_link_headers(activities) + |> put_view(StatusView) + |> render("index.json", + activities: activities, + for: user, + as: :activity + ) + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index be8988a4a4..22d0e3ecb5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -476,6 +476,8 @@ defmodule Pleroma.Web.Router do pipe_through(:api) get("/accounts/:id/favourites", AccountController, :favourites) get("/accounts/:id/endorsements", AccountController, :endorsements) + + get("/statuses/:id/quotes", StatusController, :quotes) end scope [] do