Merge branch 'following-relationships-optimizations' into 'develop'
[akkoma] / lib / pleroma / web / mastodon_api / views / account_view.ex
index 15a579278d32b0f617f3743a580556d03e299fa0..313b2f60241ee07e3f49054f9248ddbe21deeb7f 100644 (file)
@@ -5,25 +5,30 @@
 defmodule Pleroma.Web.MastodonAPI.AccountView do
   use Pleroma.Web, :view
 
+  alias Pleroma.FollowingRelationship
   alias Pleroma.User
+  alias Pleroma.UserRelationship
   alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Web.MastodonAPI.AccountView
   alias Pleroma.Web.MediaProxy
 
-  def test_rel(user_relationships, rel_type, source, target, func) do
-    cond do
-      is_nil(source) or is_nil(target) ->
-        false
+  def render("index.json", %{users: users} = opts) do
+    reading_user = opts[:for]
 
-      user_relationships ->
-        [rel_type, source.id, target.id] in user_relationships
+    relationships_opt =
+      cond do
+        Map.has_key?(opts, :relationships) ->
+          opts[:relationships]
 
-      true ->
-        func.(source, target)
-    end
-  end
+        is_nil(reading_user) ->
+          UserRelationship.view_relationships_option(nil, [])
+
+        true ->
+          UserRelationship.view_relationships_option(reading_user, users)
+      end
+
+    opts = Map.put(opts, :relationships, relationships_opt)
 
-  def render("index.json", %{users: users} = opts) do
     users
     |> render_many(AccountView, "show.json", opts)
     |> Enum.filter(&Enum.any?/1)
@@ -40,7 +45,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       id: to_string(user.id),
       acct: user.nickname,
       username: username_from_nickname(user.nickname),
-      url: User.profile_url(user)
+      url: user.uri || user.ap_id
     }
   end
 
@@ -52,22 +57,60 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         "relationship.json",
         %{user: %User{} = reading_user, target: %User{} = target} = opts
       ) do
-    user_relationships = Map.get(opts, :user_relationships)
+    user_relationships = get_in(opts, [:relationships, :user_relationships])
+    following_relationships = get_in(opts, [:relationships, :following_relationships])
+
+    follow_state =
+      if following_relationships do
+        user_to_target_following_relation =
+          FollowingRelationship.find(following_relationships, reading_user, target)
 
-    follow_state = User.get_follow_state(reading_user, target)
+        User.get_follow_state(reading_user, target, user_to_target_following_relation)
+      else
+        User.get_follow_state(reading_user, target)
+      end
 
-    # TODO: add a note on adjusting StatusView.user_relationships_opt/1 re: preloading of user relations
+    followed_by =
+      if following_relationships do
+        case FollowingRelationship.find(following_relationships, target, reading_user) do
+          %{state: :follow_accept} -> true
+          _ -> false
+        end
+      else
+        User.following?(target, reading_user)
+      end
+
+    # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
     %{
       id: to_string(target.id),
-      following: follow_state == "accept",
-      followed_by: User.following?(target, reading_user),
+      following: follow_state == :follow_accept,
+      followed_by: followed_by,
       blocking:
-        test_rel(user_relationships, :block, reading_user, target, &User.blocks_user?(&1, &2)),
+        UserRelationship.exists?(
+          user_relationships,
+          :block,
+          reading_user,
+          target,
+          &User.blocks_user?(&1, &2)
+        ),
       blocked_by:
-        test_rel(user_relationships, :block, target, reading_user, &User.blocks_user?(&1, &2)),
-      muting: test_rel(user_relationships, :mute, reading_user, target, &User.mutes?(&1, &2)),
+        UserRelationship.exists?(
+          user_relationships,
+          :block,
+          target,
+          reading_user,
+          &User.blocks_user?(&1, &2)
+        ),
+      muting:
+        UserRelationship.exists?(
+          user_relationships,
+          :mute,
+          reading_user,
+          target,
+          &User.mutes?(&1, &2)
+        ),
       muting_notifications:
-        test_rel(
+        UserRelationship.exists?(
           user_relationships,
           :notification_mute,
           reading_user,
@@ -75,17 +118,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
           &User.muted_notifications?(&1, &2)
         ),
       subscribing:
-        test_rel(
+        UserRelationship.exists?(
           user_relationships,
           :inverse_subscription,
           target,
           reading_user,
           &User.subscribed_to?(&2, &1)
         ),
-      requested: follow_state == "pending",
+      requested: follow_state == :follow_pending,
       domain_blocking: User.blocks_domain?(reading_user, target),
       showing_reblogs:
-        not test_rel(
+        not UserRelationship.exists?(
           user_relationships,
           :reblog_mute,
           reading_user,
@@ -96,8 +139,21 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
     }
   end
 
-  def render("relationships.json", %{user: user, targets: targets}) do
-    render_many(targets, AccountView, "relationship.json", user: user, as: :target)
+  def render("relationships.json", %{user: user, targets: targets} = opts) do
+    relationships_opt =
+      cond do
+        Map.has_key?(opts, :relationships) ->
+          opts[:relationships]
+
+        is_nil(user) ->
+          UserRelationship.view_relationships_option(nil, [])
+
+        true ->
+          UserRelationship.view_relationships_option(user, targets)
+      end
+
+    render_opts = %{as: :target, user: user, relationships: relationships_opt}
+    render_many(targets, AccountView, "relationship.json", render_opts)
   end
 
   defp do_render("show.json", %{user: user} = opts) do
@@ -139,7 +195,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       render("relationship.json", %{
         user: opts[:for],
         target: user,
-        user_relationships: opts[:user_relationships]
+        relationships: opts[:relationships]
       })
 
     %{
@@ -153,7 +209,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       following_count: following_count,
       statuses_count: user.note_count,
       note: user.bio || "",
-      url: User.profile_url(user),
+      url: user.uri || user.ap_id,
       avatar: image,
       avatar_static: image,
       header: header,
@@ -162,7 +218,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       fields: user.fields,
       bot: bot,
       source: %{
-        note: Pleroma.HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
+        note: (user.bio || "") |> String.replace(~r(<br */?>), "\n") |> Pleroma.HTML.strip_tags(),
         sensitive: false,
         fields: user.raw_fields,
         pleroma: %{