summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Tashkinov <ivantashkinov@gmail.com>2020-03-23 12:01:11 +0300
committerIvan Tashkinov <ivantashkinov@gmail.com>2020-03-23 12:01:11 +0300
commit3c78e5f3275494b3dc4546e65f19eb3a3c97033a (patch)
treec0353421a44c6512d36af494e84c6b1838a783cb
parentc2e415143b1dfe5d89eff06fbce6840c445aa5fa (diff)
Preloading of follow relations for timeline/statuses rendering (performance improvement). Refactoring.
-rw-r--r--lib/pleroma/following_relationship.ex26
-rw-r--r--lib/pleroma/user.ex7
-rw-r--r--lib/pleroma/user_relationship.ex13
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex75
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex46
5 files changed, 130 insertions, 37 deletions
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
index a6d281151..dd1696136 100644
--- a/lib/pleroma/following_relationship.ex
+++ b/lib/pleroma/following_relationship.ex
@@ -129,4 +129,30 @@ defmodule Pleroma.FollowingRelationship do
move_following(origin, target)
end
end
+
+ def all_between_user_sets(
+ source_users,
+ target_users
+ )
+ when is_list(source_users) and is_list(target_users) do
+ get_bin_ids = fn user ->
+ with {:ok, bin_id} <- CompatType.dump(user.id), do: bin_id
+ end
+
+ source_user_ids = Enum.map(source_users, &get_bin_ids.(&1))
+ target_user_ids = Enum.map(target_users, &get_bin_ids.(&1))
+
+ __MODULE__
+ |> where(
+ fragment(
+ "(follower_id = ANY(?) AND following_id = ANY(?)) OR \
+ (follower_id = ANY(?) AND following_id = ANY(?))",
+ ^source_user_ids,
+ ^target_user_ids,
+ ^target_user_ids,
+ ^source_user_ids
+ )
+ )
+ |> Repo.all()
+ end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index daaa6d86b..eb72755a0 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -674,7 +674,14 @@ defmodule Pleroma.User do
def get_follow_state(%User{} = follower, %User{} = following) do
following_relationship = FollowingRelationship.get(follower, following)
+ get_follow_state(follower, following, following_relationship)
+ end
+ def get_follow_state(
+ %User{} = follower,
+ %User{} = following,
+ following_relationship
+ ) do
case {following_relationship, following.local} do
{nil, false} ->
case Utils.fetch_latest_follow(follower, following) do
diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex
index 167a3919c..9423e3a42 100644
--- a/lib/pleroma/user_relationship.ex
+++ b/lib/pleroma/user_relationship.ex
@@ -116,6 +116,19 @@ defmodule Pleroma.UserRelationship do
|> Repo.all()
end
+ def exists?(dictionary, rel_type, source, target, func) do
+ cond do
+ is_nil(source) or is_nil(target) ->
+ false
+
+ dictionary ->
+ [rel_type, source.id, target.id] in dictionary
+
+ true ->
+ func.(source, target)
+ end
+ end
+
defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
changeset
|> validate_change(:target_id, fn _, target_id ->
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 15a579278..2fe46158b 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -6,21 +6,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
use Pleroma.Web, :view
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
-
- user_relationships ->
- [rel_type, source.id, target.id] in user_relationships
-
- true ->
- func.(source, target)
- end
+ defp find_following_rel(following_relationships, follower, following) do
+ Enum.find(following_relationships, fn
+ fr -> fr.follower_id == follower.id and fr.following_id == following.id
+ end)
end
def render("index.json", %{users: users} = opts) do
@@ -53,21 +47,61 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
%{user: %User{} = reading_user, target: %User{} = target} = opts
) do
user_relationships = Map.get(opts, :user_relationships)
+ following_relationships = opts[:following_relationships]
+
+ follow_state =
+ if following_relationships do
+ user_to_target_following_relation =
+ find_following_rel(following_relationships, reading_user, target)
+
+ User.get_follow_state(reading_user, target, user_to_target_following_relation)
+ else
+ User.get_follow_state(reading_user, target)
+ end
- follow_state = User.get_follow_state(reading_user, target)
+ followed_by =
+ if following_relationships do
+ with %{state: "accept"} <-
+ find_following_rel(following_relationships, target, reading_user) do
+ true
+ else
+ _ -> false
+ end
+ else
+ User.following?(target, reading_user)
+ end
# TODO: add a note on adjusting StatusView.user_relationships_opt/1 re: preloading of user relations
%{
id: to_string(target.id),
following: follow_state == "accept",
- followed_by: User.following?(target, reading_user),
+ 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,7 +109,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
&User.muted_notifications?(&1, &2)
),
subscribing:
- test_rel(
+ UserRelationship.exists?(
user_relationships,
:inverse_subscription,
target,
@@ -85,7 +119,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
requested: follow_state == "pending",
domain_blocking: User.blocks_domain?(reading_user, target),
showing_reblogs:
- not test_rel(
+ not UserRelationship.exists?(
user_relationships,
:reblog_mute,
reading_user,
@@ -139,7 +173,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
render("relationship.json", %{
user: opts[:for],
target: user,
- user_relationships: opts[:user_relationships]
+ user_relationships: opts[:user_relationships],
+ following_relationships: opts[:following_relationships]
})
%{
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index e0c368ec9..55a5513f9 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
alias Pleroma.Activity
alias Pleroma.ActivityExpiration
+ alias Pleroma.FollowingRelationship
alias Pleroma.HTML
alias Pleroma.Object
alias Pleroma.Repo
@@ -71,22 +72,31 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
present?(user && user.ap_id in (object.data["announcements"] || []))
end
- defp user_relationships_opt(opts) do
+ defp relationships_opts(opts) do
reading_user = opts[:for]
- if reading_user do
- activities = opts[:activities]
- actors = Enum.map(activities, fn a -> get_user(a.data["actor"]) end)
+ {user_relationships, following_relationships} =
+ if reading_user do
+ activities = opts[:activities]
+ actors = Enum.map(activities, fn a -> get_user(a.data["actor"]) end)
- UserRelationship.dictionary(
- [reading_user],
- actors,
- [:block, :mute, :notification_mute, :reblog_mute],
- [:block, :inverse_subscription]
- )
- else
- []
- end
+ user_relationships =
+ UserRelationship.dictionary(
+ [reading_user],
+ actors,
+ [:block, :mute, :notification_mute, :reblog_mute],
+ [:block, :inverse_subscription]
+ )
+
+ following_relationships =
+ FollowingRelationship.all_between_user_sets([reading_user], actors)
+
+ {user_relationships, following_relationships}
+ else
+ {[], []}
+ end
+
+ %{user_relationships: user_relationships, following_relationships: following_relationships}
end
def render("index.json", opts) do
@@ -96,7 +106,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
opts =
opts
|> Map.put(:replied_to_activities, replied_to_activities)
- |> Map.put(:user_relationships, user_relationships_opt(opts))
+ |> Map.merge(relationships_opts(opts))
safe_render_many(activities, StatusView, "show.json", opts)
end
@@ -135,7 +145,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
AccountView.render("show.json", %{
user: user,
for: opts[:for],
- user_relationships: opts[:user_relationships]
+ user_relationships: opts[:user_relationships],
+ following_relationships: opts[:following_relationships]
}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
@@ -286,7 +297,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
muted =
thread_muted? ||
- Pleroma.Web.MastodonAPI.AccountView.test_rel(
+ UserRelationship.exists?(
user_relationships_opt,
:mute,
opts[:for],
@@ -302,7 +313,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
AccountView.render("show.json", %{
user: user,
for: opts[:for],
- user_relationships: user_relationships_opt
+ user_relationships: user_relationships_opt,
+ following_relationships: opts[:following_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),