Ability to control the output of account/pleroma/relationship in statuses in order...
authorIvan Tashkinov <ivantashkinov@gmail.com>
Wed, 1 Apr 2020 16:49:09 +0000 (19:49 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Wed, 1 Apr 2020 16:49:09 +0000 (19:49 +0300)
See `[:extensions, output_relationships_in_statuses_by_default]` setting and `with_relationships` param.

25 files changed:
CHANGELOG.md
benchmarks/load_testing/fetcher.ex
config/config.exs
config/description.exs
lib/mix/tasks/pleroma/benchmark.ex
lib/pleroma/user_relationship.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/admin_api/views/report_view.ex
lib/pleroma/web/common_api/activity_draft.ex
lib/pleroma/web/controller_helper.ex
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
lib/pleroma/web/mastodon_api/controllers/search_controller.ex
lib/pleroma/web/mastodon_api/controllers/status_controller.ex
lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
lib/pleroma/web/mastodon_api/views/account_view.ex
lib/pleroma/web/mastodon_api/views/notification_view.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/pleroma_api/controllers/account_controller.ex
lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs
priv/repo/migrations/20190711042021_create_safe_jsonb_set.exs
test/web/mastodon_api/controllers/notification_controller_test.exs
test/web/mastodon_api/controllers/status_controller_test.exs
test/web/mastodon_api/controllers/timeline_controller_test.exs

index 350e03894ff1895f63bd5d0542c905ff78fb3487..a391bf1fa2ffdc45869f9ca33031ba30b33b6f79 100644 (file)
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ### Added
 - NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
 - Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
+- Configuration: `:extensions/:output_relationships_in_statuses_by_default` option (if `false`, disables the output of account/pleroma/relationship for statuses and notifications by default, breaking the compatibility with older PleromaFE versions).
 <details>
   <summary>API Changes</summary>
 - Mastodon API: Support for `include_types` in `/api/v1/notifications`.
@@ -20,7 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## [2.0.0] - 2019-03-08
 ### Security
-- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
+- Mastodon API: Fix being able to request enormous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
 
 ### Removed
 - **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
index bd65ac84fcbc548ac8a880da07222ec040d10091..786929ace9faa1989e96e2896f554b7a6c533116 100644 (file)
@@ -386,47 +386,56 @@ defmodule Pleroma.LoadTesting.Fetcher do
 
     favourites = ActivityPub.fetch_favourites(user)
 
+    output_relationships =
+      !!Pleroma.Config.get([:extensions, :output_relationships_in_statuses_by_default])
+
     Benchee.run(
       %{
         "Rendering home timeline" => fn ->
           StatusView.render("index.json", %{
             activities: home_activities,
             for: user,
-            as: :activity
+            as: :activity,
+            skip_relationships: !output_relationships
           })
         end,
         "Rendering direct timeline" => fn ->
           StatusView.render("index.json", %{
             activities: direct_activities,
             for: user,
-            as: :activity
+            as: :activity,
+            skip_relationships: !output_relationships
           })
         end,
         "Rendering public timeline" => fn ->
           StatusView.render("index.json", %{
             activities: public_activities,
             for: user,
-            as: :activity
+            as: :activity,
+            skip_relationships: !output_relationships
           })
         end,
         "Rendering tag timeline" => fn ->
           StatusView.render("index.json", %{
             activities: tag_activities,
             for: user,
-            as: :activity
+            as: :activity,
+            skip_relationships: !output_relationships
           })
         end,
         "Rendering notifications" => fn ->
           Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
             notifications: notifications,
-            for: user
+            for: user,
+            skip_relationships: !output_relationships
           })
         end,
         "Rendering favourites timeline" => fn ->
           StatusView.render("index.json", %{
             activities: favourites,
             for: user,
-            as: :activity
+            as: :activity,
+            skip_relationships: !output_relationships
           })
         end
       },
index 2ab9391074f9851c0ff85b29884a63b26da7f174..73bf658fe07c1d02e405551057dabe7b60f7c6e2 100644 (file)
@@ -262,6 +262,8 @@ config :pleroma, :instance,
   extended_nickname_format: true,
   cleanup_attachments: false
 
+config :pleroma, :extensions, output_relationships_in_statuses_by_default: true
+
 config :pleroma, :feed,
   post_title: %{
     max_length: 100,
index 9612adba7a53cbd105d19ca86a3dd1f7e9318568..d127f8f203a3d46c43911e9f94f880e153f74567 100644 (file)
@@ -121,6 +121,22 @@ config :pleroma, :config_description, [
       }
     ]
   },
+  %{
+    group: :pleroma,
+    key: :extensions,
+    type: :group,
+    description: "Pleroma-specific extensions",
+    children: [
+      %{
+        key: :output_relationships_in_statuses_by_default,
+        type: :beeolean,
+        description:
+          "If `true`, outputs account/pleroma/relationship map for each rendered status / notification (for all clients). " <>
+            "If `false`, outputs the above only if `with_relationships` param is tru-ish " <>
+            "(that breaks compatibility with older PleromaFE versions which do not send this param but expect the output)."
+      }
+    ]
+  },
   %{
     group: :pleroma,
     key: Pleroma.Uploaders.Local,
index a4885b70cd74205d0c27cd91f3496db307199308..b2bbe40ac7aca04a600d274df8faa446b6dd5dd9 100644 (file)
@@ -67,7 +67,8 @@ defmodule Mix.Tasks.Pleroma.Benchmark do
           Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
             activities: activities,
             for: user,
-            as: :activity
+            as: :activity,
+            skip_relationships: true
           })
         end
       },
index 18a5eec7262bc1816753dea928b64025ebe08deb..d42dc250e5bc561348ec7a0acb38167c2d8507c1 100644 (file)
@@ -129,17 +129,27 @@ defmodule Pleroma.UserRelationship do
   end
 
   @doc ":relationships option for StatusView / AccountView / NotificationView"
-  def view_relationships_option(nil = _reading_user, _actors) do
+  def view_relationships_option(reading_user, actors, opts \\ [])
+
+  def view_relationships_option(nil = _reading_user, _actors, _opts) do
     %{user_relationships: [], following_relationships: []}
   end
 
-  def view_relationships_option(%User{} = reading_user, actors) do
+  def view_relationships_option(%User{} = reading_user, actors, opts) do
+    {source_to_target_rel_types, target_to_source_rel_types} =
+      if opts[:source_mutes_only] do
+        # This option is used for rendering statuses (FE needs `muted` flag for each one anyways)
+        {[:mute], []}
+      else
+        {[:block, :mute, :notification_mute, :reblog_mute], [:block, :inverse_subscription]}
+      end
+
     user_relationships =
       UserRelationship.dictionary(
         [reading_user],
         actors,
-        [:block, :mute, :notification_mute, :reblog_mute],
-        [:block, :inverse_subscription]
+        source_to_target_rel_types,
+        target_to_source_rel_types
       )
 
     following_relationships = FollowingRelationship.all_between_user_sets([reading_user], actors)
index ca54399204c0357141788433ad004ab1b0e72322..747d97f805783b034050f7c56a5d838f073456f7 100644 (file)
@@ -258,7 +258,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
 
     conn
     |> put_view(Pleroma.Web.AdminAPI.StatusView)
-    |> render("index.json", %{activities: activities, as: :activity})
+    |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
   end
 
   def list_user_statuses(conn, %{"nickname" => nickname} = params) do
@@ -277,7 +277,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
 
       conn
       |> put_view(StatusView)
-      |> render("index.json", %{activities: activities, as: :activity})
+      |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
     else
       _ -> {:error, :not_found}
     end
@@ -801,7 +801,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
 
     conn
     |> put_view(Pleroma.Web.AdminAPI.StatusView)
-    |> render("index.json", %{activities: activities, as: :activity})
+    |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
   end
 
   def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
index ca0bcebc751a138aa66dca1888a5fa0e0c111d57..d50969b2a7a4712e63c619d42dcbb57950cd6006 100644 (file)
@@ -38,7 +38,12 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
       actor: merge_account_views(user),
       content: content,
       created_at: created_at,
-      statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
+      statuses:
+        StatusView.render("index.json", %{
+          activities: statuses,
+          as: :activity,
+          skip_relationships: false
+        }),
       state: report.data["state"],
       notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
     }
index c4356f93bd341f08f657fc45ebc2462625826447..c1cd15bb2a37ba98e923f50ab50dc7083995fc9c 100644 (file)
@@ -187,7 +187,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
   end
 
   defp preview?(draft) do
-    preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"]) || false
+    preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"])
     %__MODULE__{draft | preview?: preview?}
   end
 
index b49523ec38513455a20f88c5daea3ab2be812f94..4780081b26868bb3ba08f6b508ed14782fbe3999 100644 (file)
@@ -5,10 +5,18 @@
 defmodule Pleroma.Web.ControllerHelper do
   use Pleroma.Web, :controller
 
-  # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+  alias Pleroma.Config
+
+  # As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
   @falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
-  def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
-  def truthy_param?(value), do: value not in @falsy_param_values
+
+  def explicitly_falsy_param?(value), do: value in @falsy_param_values
+
+  # Note: `nil` and `""` are considered falsy values in Pleroma
+  def falsy_param?(value),
+    do: explicitly_falsy_param?(value) or value in [nil, ""]
+
+  def truthy_param?(value), do: not falsy_param?(value)
 
   def json_response(conn, status, json) do
     conn
@@ -96,4 +104,14 @@ defmodule Pleroma.Web.ControllerHelper do
   def put_if_exist(map, _key, nil), do: map
 
   def put_if_exist(map, key, value), do: Map.put(map, key, value)
+
+  @doc "Whether to skip rendering `[:account][:pleroma][:relationship]`for statuses/notifications"
+  def skip_relationships?(params) do
+    if Config.get([:extensions, :output_relationships_in_statuses_by_default]) do
+      false
+    else
+      # BREAKING: older PleromaFE versions do not send this param but _do_ expect relationships.
+      not truthy_param?(params["with_relationships"])
+    end
+  end
 end
index 21bc3d5a549d5fde33a633c00f1147df3968deb4..7da1a11f63fb9caeadb833057c98ab1377eea3ee 100644 (file)
@@ -6,7 +6,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
   use Pleroma.Web, :controller
 
   import Pleroma.Web.ControllerHelper,
-    only: [add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, json_response: 3]
+    only: [
+      add_link_headers: 2,
+      truthy_param?: 1,
+      assign_account_by_id: 2,
+      json_response: 3,
+      skip_relationships?: 1
+    ]
 
   alias Pleroma.Plugs.OAuthScopesPlug
   alias Pleroma.Plugs.RateLimiter
@@ -237,7 +243,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
       conn
       |> add_link_headers(activities)
       |> put_view(StatusView)
-      |> render("index.json", activities: activities, for: reading_user, as: :activity)
+      |> render("index.json",
+        activities: activities,
+        for: reading_user,
+        as: :activity,
+        skip_relationships: skip_relationships?(params)
+      )
     else
       _e -> render_error(conn, :not_found, "Can't find user")
     end
index 0c9218454454768fee8f9335e1cd10c5e9f5d57a..c7e808253f038c00321d810a93f51d6c82761c18 100644 (file)
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.MastodonAPI.NotificationController do
   use Pleroma.Web, :controller
 
-  import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+  import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
 
   alias Pleroma.Notification
   alias Pleroma.Plugs.OAuthScopesPlug
@@ -45,7 +45,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
 
     conn
     |> add_link_headers(notifications)
-    |> render("index.json", notifications: notifications, for: user)
+    |> render("index.json",
+      notifications: notifications,
+      for: user,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   # GET /api/v1/notifications/:id
index fcab4ef63e22fa2c5e4944f18b94fd40bf46f727..c258742dd80eacb710dac953650dbe9d73b0298c 100644 (file)
@@ -5,13 +5,14 @@
 defmodule Pleroma.Web.MastodonAPI.SearchController do
   use Pleroma.Web, :controller
 
+  import Pleroma.Web.ControllerHelper, only: [fetch_integer_param: 2, skip_relationships?: 1]
+
   alias Pleroma.Activity
   alias Pleroma.Plugs.OAuthScopesPlug
   alias Pleroma.Plugs.RateLimiter
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web
-  alias Pleroma.Web.ControllerHelper
   alias Pleroma.Web.MastodonAPI.AccountView
   alias Pleroma.Web.MastodonAPI.StatusView
 
@@ -66,10 +67,11 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
 
   defp search_options(params, user) do
     [
+      skip_relationships: skip_relationships?(params),
       resolve: params["resolve"] == "true",
       following: params["following"] == "true",
-      limit: ControllerHelper.fetch_integer_param(params, "limit"),
-      offset: ControllerHelper.fetch_integer_param(params, "offset"),
+      limit: fetch_integer_param(params, "limit"),
+      offset: fetch_integer_param(params, "offset"),
       type: params["type"],
       author: get_author(params),
       for_user: user
@@ -79,12 +81,24 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
 
   defp resource_search(_, "accounts", query, options) do
     accounts = with_fallback(fn -> User.search(query, options) end)
-    AccountView.render("index.json", users: accounts, for: options[:for_user], as: :user)
+
+    AccountView.render("index.json",
+      users: accounts,
+      for: options[:for_user],
+      as: :user,
+      skip_relationships: false
+    )
   end
 
   defp resource_search(_, "statuses", query, options) do
     statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
-    StatusView.render("index.json", activities: statuses, for: options[:for_user], as: :activity)
+
+    StatusView.render("index.json",
+      activities: statuses,
+      for: options[:for_user],
+      as: :activity,
+      skip_relationships: options[:skip_relationships]
+    )
   end
 
   defp resource_search(:v2, "hashtags", query, _options) do
index 37afe6949f29f1e116beb5f6c1d88fdf3c19852f..eb3d90aebc520c27ce9691d6890cf39f2dd422d6 100644 (file)
@@ -5,7 +5,8 @@
 defmodule Pleroma.Web.MastodonAPI.StatusController do
   use Pleroma.Web, :controller
 
-  import Pleroma.Web.ControllerHelper, only: [try_render: 3, add_link_headers: 2]
+  import Pleroma.Web.ControllerHelper,
+    only: [try_render: 3, add_link_headers: 2, skip_relationships?: 1]
 
   require Ecto.Query
 
@@ -101,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
 
   `ids` query param is required
   """
-  def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
+  def index(%{assigns: %{user: user}} = conn, %{"ids" => ids} = params) do
     limit = 100
 
     activities =
@@ -110,7 +111,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
       |> Activity.all_by_ids_with_object()
       |> Enum.filter(&Visibility.visible_for_user?(&1, user))
 
-    render(conn, "index.json", activities: activities, for: user, as: :activity)
+    render(conn, "index.json",
+      activities: activities,
+      for: user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   @doc """
@@ -360,7 +366,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
 
     conn
     |> add_link_headers(activities)
-    |> render("index.json", activities: activities, for: user, as: :activity)
+    |> render("index.json",
+      activities: activities,
+      for: user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   @doc "GET /api/v1/bookmarks"
@@ -378,6 +389,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
 
     conn
     |> add_link_headers(bookmarks)
-    |> render("index.json", %{activities: activities, for: user, as: :activity})
+    |> render("index.json",
+      activities: activities,
+      for: user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 end
index 91f41416d4aad5381a1ee80c9989e0af34dfc905..b3c58005eb170e6a2cbebef154eb63449ce2732f 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
   use Pleroma.Web, :controller
 
   import Pleroma.Web.ControllerHelper,
-    only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1]
+    only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1, skip_relationships?: 1]
 
   alias Pleroma.Pagination
   alias Pleroma.Plugs.OAuthScopesPlug
@@ -14,9 +14,8 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
 
-  # TODO: Replace with a macro when there is a Phoenix release with
+  # TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
   # https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
-  # in it
 
   plug(RateLimiter, [name: :timeline, bucket_name: :direct_timeline] when action == :direct)
   plug(RateLimiter, [name: :timeline, bucket_name: :public_timeline] when action == :public)
@@ -49,7 +48,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
 
     conn
     |> add_link_headers(activities)
-    |> render("index.json", activities: activities, for: user, as: :activity)
+    |> render("index.json",
+      activities: activities,
+      for: user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   # GET /api/v1/timelines/direct
@@ -68,7 +72,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
 
     conn
     |> add_link_headers(activities)
-    |> render("index.json", activities: activities, for: user, as: :activity)
+    |> render("index.json",
+      activities: activities,
+      for: user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   # GET /api/v1/timelines/public
@@ -95,7 +104,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
 
       conn
       |> add_link_headers(activities, %{"local" => local_only})
-      |> render("index.json", activities: activities, for: user, as: :activity)
+      |> render("index.json",
+        activities: activities,
+        for: user,
+        as: :activity,
+        skip_relationships: skip_relationships?(params)
+      )
     else
       render_error(conn, :unauthorized, "authorization required for timeline view")
     end
@@ -140,7 +154,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
 
     conn
     |> add_link_headers(activities, %{"local" => local_only})
-    |> render("index.json", activities: activities, for: user, as: :activity)
+    |> render("index.json",
+      activities: activities,
+      for: user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   # GET /api/v1/timelines/list/:list_id
@@ -164,7 +183,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
         |> ActivityPub.fetch_activities_bounded(following, params)
         |> Enum.reverse()
 
-      render(conn, "index.json", activities: activities, for: user, as: :activity)
+      render(conn, "index.json",
+        activities: activities,
+        for: user,
+        as: :activity,
+        skip_relationships: skip_relationships?(params)
+      )
     else
       _e -> render_error(conn, :forbidden, "Error.")
     end
index c482bba6498d4c806e37a9b540663c84eb8506b6..b20a00a89161bfe1ce7808592a4cc7f83cd039e3 100644 (file)
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
   alias Pleroma.Web.MediaProxy
 
   def render("index.json", %{users: users} = opts) do
+    # Note: :skip_relationships option is currently intentionally not supported for accounts
     relationships_opt =
       cond do
         Map.has_key?(opts, :relationships) ->
@@ -190,11 +191,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       end)
 
     relationship =
-      render("relationship.json", %{
-        user: opts[:for],
-        target: user,
-        relationships: opts[:relationships]
-      })
+      if opts[:skip_relationships] do
+        %{}
+      else
+        render("relationship.json", %{
+          user: opts[:for],
+          target: user,
+          relationships: opts[:relationships]
+        })
+      end
 
     %{
       id: to_string(user.id),
index 89f5734ffaee84d618dd260fc18f5b5798b3ba12..78d187f9a8e15646d42837680aca03ababf6733f 100644 (file)
@@ -51,14 +51,15 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
             |> Enum.filter(& &1)
             |> Kernel.++(move_activities_targets)
 
-          UserRelationship.view_relationships_option(reading_user, actors)
+          UserRelationship.view_relationships_option(reading_user, actors,
+            source_mutes_only: opts[:skip_relationships]
+          )
       end
 
-    opts = %{
-      for: reading_user,
-      parent_activities: parent_activities,
-      relationships: relationships_opt
-    }
+    opts =
+      opts
+      |> Map.put(:parent_activities, parent_activities)
+      |> Map.put(:relationships, relationships_opt)
 
     safe_render_many(notifications, NotificationView, "show.json", opts)
   end
@@ -82,12 +83,16 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
 
     mastodon_type = Activity.mastodon_notification_type(activity)
 
+    render_opts = %{
+      relationships: opts[:relationships],
+      skip_relationships: opts[:skip_relationships]
+    }
+
     with %{id: _} = account <-
-           AccountView.render("show.json", %{
-             user: actor,
-             for: reading_user,
-             relationships: opts[:relationships]
-           }) do
+           AccountView.render(
+             "show.json",
+             Map.merge(render_opts, %{user: actor, for: reading_user})
+           ) do
       response = %{
         id: to_string(notification.id),
         type: mastodon_type,
@@ -98,8 +103,6 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
         }
       }
 
-      render_opts = %{relationships: opts[:relationships]}
-
       case mastodon_type do
         "mention" ->
           put_status(response, activity, reading_user, render_opts)
@@ -111,6 +114,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
           put_status(response, parent_activity_fn.(), reading_user, render_opts)
 
         "move" ->
+          # Note: :skip_relationships option being applied to _account_ rendering (here)
           put_target(response, activity, reading_user, render_opts)
 
         "follow" ->
index 82326986ced11047de3a18206d5673af45605ff1..9cbd31878b5b8ce939903c98d9650002e7eb5b71 100644 (file)
@@ -97,7 +97,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
         true ->
           actors = Enum.map(activities ++ parent_activities, &get_user(&1.data["actor"]))
 
-          UserRelationship.view_relationships_option(opts[:for], actors)
+          UserRelationship.view_relationships_option(opts[:for], actors,
+            source_mutes_only: opts[:skip_relationships]
+          )
       end
 
     opts =
@@ -151,7 +153,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
         AccountView.render("show.json", %{
           user: user,
           for: opts[:for],
-          relationships: opts[:relationships]
+          relationships: opts[:relationships],
+          skip_relationships: opts[:skip_relationships]
         }),
       in_reply_to_id: nil,
       in_reply_to_account_id: nil,
@@ -299,6 +302,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
         _ -> []
       end
 
+    # Status muted state (would do 1 request per status unless user mutes are preloaded)
     muted =
       thread_muted? ||
         UserRelationship.exists?(
@@ -317,7 +321,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
         AccountView.render("show.json", %{
           user: user,
           for: opts[:for],
-          relationships: opts[:relationships]
+          relationships: opts[:relationships],
+          skip_relationships: opts[:skip_relationships]
         }),
       in_reply_to_id: reply_to && to_string(reply_to.id),
       in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
index dcba67d038bfcff8fdecb49d9660542a0f19c536..9d0b3b1e45cf0620904ef6f7067fa4bf261bcdd0 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
   use Pleroma.Web, :controller
 
   import Pleroma.Web.ControllerHelper,
-    only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
+    only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2, skip_relationships?: 1]
 
   alias Ecto.Changeset
   alias Pleroma.Plugs.OAuthScopesPlug
@@ -139,7 +139,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
     conn
     |> add_link_headers(activities)
     |> put_view(StatusView)
-    |> render("index.json", activities: activities, for: for_user, as: :activity)
+    |> render("index.json",
+      activities: activities,
+      for: for_user,
+      as: :activity,
+      skip_relationships: skip_relationships?(params)
+    )
   end
 
   @doc "POST /api/v1/pleroma/accounts/:id/subscribe"
index dae7f0f2f7aff92eab595b1f80e1bf332937f1b2..83983b5761988666ecf77edc1d07ae3758ff5db5 100644 (file)
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
   use Pleroma.Web, :controller
 
-  import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+  import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
 
   alias Pleroma.Activity
   alias Pleroma.Conversation.Participation
@@ -130,7 +130,12 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
       conn
       |> add_link_headers(activities)
       |> put_view(StatusView)
-      |> render("index.json", %{activities: activities, for: user, as: :activity})
+      |> render("index.json",
+        activities: activities,
+        for: user,
+        as: :activity,
+        skip_relationships: skip_relationships?(params)
+      )
     else
       _error ->
         conn
@@ -184,13 +189,17 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
     end
   end
 
-  def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
+  def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
     with notifications <- Notification.set_read_up_to(user, max_id) do
       notifications = Enum.take(notifications, 80)
 
       conn
       |> put_view(NotificationView)
-      |> render("index.json", %{notifications: notifications, for: user})
+      |> render("index.json",
+        notifications: notifications,
+        for: user,
+        skip_relationships: skip_relationships?(params)
+      )
     end
   end
 end
index c618ea3817dae9890a51fd04200e55df8a0c7796..b6f0ac66b3dde98f6a1e95d9b38edeceed381788 100644 (file)
@@ -3,7 +3,6 @@ defmodule Pleroma.Repo.Migrations.MigrateOldBookmarks do
   import Ecto.Query
   alias Pleroma.Activity
   alias Pleroma.Bookmark
-  alias Pleroma.User
   alias Pleroma.Repo
 
   def up do
index 2f336a5e84659b98d04dea60ce43b62cbb2ada28..43d61670555ad019d4fe1b7659d12d23f508b79d 100644 (file)
@@ -1,6 +1,5 @@
 defmodule Pleroma.Repo.Migrations.CreateSafeJsonbSet do
   use Ecto.Migration
-  alias Pleroma.User
 
   def change do
     execute("""
index 7a001164633d0f2934e479fda610a287d0a774e3..42a311f99ce42c585030ce3698ebd52401cd92a8 100644 (file)
@@ -12,6 +12,26 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
 
   import Pleroma.Factory
 
+  test "does NOT render account/pleroma/relationship if this is disabled by default" do
+    clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
+
+    %{user: user, conn: conn} = oauth_access(["read:notifications"])
+    other_user = insert(:user)
+
+    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
+    {:ok, [_notification]} = Notification.create_notifications(activity)
+
+    response =
+      conn
+      |> assign(:user, user)
+      |> get("/api/v1/notifications")
+      |> json_response(200)
+
+    assert Enum.all?(response, fn n ->
+             get_in(n, ["account", "pleroma", "relationship"]) == %{}
+           end)
+  end
+
   test "list of notifications" do
     %{user: user, conn: conn} = oauth_access(["read:notifications"])
     other_user = insert(:user)
index d59974d50bf479dc236ac2a0d954e917a36b6a86..6b126217a50031b51a4df49d8cb7d292b134f515 100644 (file)
@@ -1043,6 +1043,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
   end
 
   test "bookmarks" do
+    bookmarks_uri = "/api/v1/bookmarks?with_relationships=true"
+
     %{conn: conn} = oauth_access(["write:bookmarks", "read:bookmarks"])
     author = insert(:user)
 
@@ -1064,7 +1066,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
 
     assert json_response(response2, 200)["bookmarked"] == true
 
-    bookmarks = get(conn, "/api/v1/bookmarks")
+    bookmarks = get(conn, bookmarks_uri)
 
     assert [json_response(response2, 200), json_response(response1, 200)] ==
              json_response(bookmarks, 200)
@@ -1073,7 +1075,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
 
     assert json_response(response1, 200)["bookmarked"] == false
 
-    bookmarks = get(conn, "/api/v1/bookmarks")
+    bookmarks = get(conn, bookmarks_uri)
 
     assert [json_response(response2, 200)] == json_response(bookmarks, 200)
   end
index 97b1c3e66c35b06d82d1488d1b3b89b0a6f19f6f..06efdc901aa763ae6dd58a7628b544f5a06c0a43 100644 (file)
@@ -20,7 +20,30 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
   describe "home" do
     setup do: oauth_access(["read:statuses"])
 
+    test "does NOT render account/pleroma/relationship if this is disabled by default", %{
+      user: user,
+      conn: conn
+    } do
+      clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
+
+      other_user = insert(:user)
+
+      {:ok, _} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/timelines/home")
+        |> json_response(200)
+
+      assert Enum.all?(response, fn n ->
+               get_in(n, ["account", "pleroma", "relationship"]) == %{}
+             end)
+    end
+
     test "the home timeline", %{user: user, conn: conn} do
+      uri = "/api/v1/timelines/home?with_relationships=true"
+
       following = insert(:user, nickname: "followed")
       third_user = insert(:user, nickname: "repeated")
 
@@ -28,13 +51,13 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
       {:ok, activity} = CommonAPI.post(third_user, %{"status" => "repeated post"})
       {:ok, _, _} = CommonAPI.repeat(activity.id, following)
 
-      ret_conn = get(conn, "/api/v1/timelines/home")
+      ret_conn = get(conn, uri)
 
       assert Enum.empty?(json_response(ret_conn, :ok))
 
       {:ok, _user} = User.follow(user, following)
 
-      ret_conn = get(conn, "/api/v1/timelines/home")
+      ret_conn = get(conn, uri)
 
       assert [
                %{
@@ -59,7 +82,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
 
       {:ok, _user} = User.follow(third_user, user)
 
-      ret_conn = get(conn, "/api/v1/timelines/home")
+      ret_conn = get(conn, uri)
 
       assert [
                %{