Load all users at once in timelines.

This commit is contained in:
lain 2018-04-02 16:27:36 +02:00
parent 96007753ad
commit b3b7ab5d9a
5 changed files with 94 additions and 30 deletions

View file

@ -50,10 +50,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do
changeset = Object.context_mapping(context) changeset = Object.context_mapping(context)
case Repo.insert(changeset) do case Repo.insert(changeset) do
{:ok, object} -> object {:ok, object} ->
object
# This should be solved by an upsert, but it seems ecto # This should be solved by an upsert, but it seems ecto
# has problems accessing the constraint inside the jsonb. # has problems accessing the constraint inside the jsonb.
{:error, _} -> Object.get_cached_by_ap_id(context) {:error, _} ->
Object.get_cached_by_ap_id(context)
end end
end end

View file

@ -513,7 +513,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
) )
statuses = Repo.all(q) ++ fetched statuses = Repo.all(q) ++ fetched
tags = String.split(query)
tags =
String.split(query)
|> Enum.uniq() |> Enum.uniq()
|> Enum.filter(fn tag -> String.starts_with?(tag, "#") end) |> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
|> Enum.map(fn tag -> String.slice(tag, 1..-1) end) |> Enum.map(fn tag -> String.slice(tag, 1..-1) end)

View file

@ -8,46 +8,99 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Formatter alias Pleroma.Formatter
import Ecto.Query import Ecto.Query
defp query_context_ids([]), do: [] defp query_context_ids([]), do: []
defp query_context_ids(contexts) do defp query_context_ids(contexts) do
query = from o in Object, query = from(o in Object, where: fragment("(?)->>'id' = ANY(?)", o.data, ^contexts))
where: fragment("(?)->>'id' = ANY(?)", o.data, ^contexts)
Repo.all(query)
end
defp query_users([]), do: []
defp query_users(user_ids) do
query = from(user in User, where: user.ap_id in ^user_ids)
Repo.all(query) Repo.all(query)
end end
defp collect_context_ids(activities) do defp collect_context_ids(activities) do
contexts = activities contexts =
|> Enum.reject(&(&1.data["context_id"])) activities
|> Enum.map(fn(%{data: data}) -> |> Enum.reject(& &1.data["context_id"])
|> Enum.map(fn %{data: data} ->
data["context"] data["context"]
end) end)
|> Enum.filter(&(&1)) |> Enum.filter(& &1)
|> query_context_ids() |> query_context_ids()
|> Enum.reduce(%{}, fn(%{data: %{"id" => ap_id}, id: id}, acc) -> |> Enum.reduce(%{}, fn %{data: %{"id" => ap_id}, id: id}, acc ->
Map.put(acc, ap_id, id) Map.put(acc, ap_id, id)
end) end)
end end
defp get_context_id(%{data: %{"context_id" => context_id}}, _) when not is_nil(context_id), do: context_id defp collect_users(activities) do
activities
|> Enum.map(fn activity ->
case activity.data do
data = %{"type" => "Follow"} ->
[data["actor"], data["object"]]
data ->
[data["actor"]]
end ++ activity.recipients
end)
|> List.flatten()
|> Enum.uniq()
|> query_users()
|> Enum.reduce(%{}, fn user, acc ->
Map.put(acc, user.ap_id, user)
end)
end
defp get_context_id(%{data: %{"context_id" => context_id}}, _) when not is_nil(context_id),
do: context_id
defp get_context_id(%{data: %{"context" => nil}}, _), do: nil defp get_context_id(%{data: %{"context" => nil}}, _), do: nil
defp get_context_id(%{data: %{"context" => context}}, options) do defp get_context_id(%{data: %{"context" => context}}, options) do
cond do cond do
id = options[:context_ids][context] -> id id = options[:context_ids][context] -> id
true -> TwitterAPI.context_to_conversation_id(context) true -> TwitterAPI.context_to_conversation_id(context)
end end
end end
defp get_context_id(_, _), do: nil defp get_context_id(_, _), do: nil
defp get_user(ap_id, opts) do
cond do
user = opts[:users][ap_id] ->
user
String.ends_with?(ap_id, "/followers") ->
nil
ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
nil
true ->
User.get_cached_by_ap_id(ap_id)
end
end
def render("index.json", opts) do def render("index.json", opts) do
context_ids = collect_context_ids(opts.activities) context_ids = collect_context_ids(opts.activities)
opts = opts users = collect_users(opts.activities)
opts =
opts
|> Map.put(:context_ids, context_ids) |> Map.put(:context_ids, context_ids)
|> Map.put(:users, users)
render_many( render_many(
opts.activities, opts.activities,
@ -58,7 +111,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
end end
def render("activity.json", %{activity: %{data: %{"type" => "Delete"}} = activity} = opts) do def render("activity.json", %{activity: %{data: %{"type" => "Delete"}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"]) user = get_user(activity.data["actor"], opts)
created_at = activity.data["published"] |> Utils.date_to_asctime() created_at = activity.data["published"] |> Utils.date_to_asctime()
%{ %{
@ -78,11 +131,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
end end
def render("activity.json", %{activity: %{data: %{"type" => "Follow"}} = activity} = opts) do def render("activity.json", %{activity: %{data: %{"type" => "Follow"}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"]) user = get_user(activity.data["actor"], opts)
created_at = activity.data["published"] || DateTime.to_iso8601(activity.inserted_at) created_at = activity.data["published"] || DateTime.to_iso8601(activity.inserted_at)
created_at = created_at |> Utils.date_to_asctime() created_at = created_at |> Utils.date_to_asctime()
followed = User.get_cached_by_ap_id(activity.data["object"]) followed = get_user(activity.data["object"], opts)
text = "#{user.nickname} started following #{followed.nickname}" text = "#{user.nickname} started following #{followed.nickname}"
%{ %{
@ -101,7 +154,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
end end
def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activity} = opts) do def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activity} = opts) do
user = User.get_by_ap_id(activity.data["actor"]) user = get_user(activity.data["actor"], opts)
created_at = activity.data["published"] |> Utils.date_to_asctime() created_at = activity.data["published"] |> Utils.date_to_asctime()
announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]) announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
@ -126,7 +179,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
end end
def render("activity.json", %{activity: %{data: %{"type" => "Like"}} = activity} = opts) do def render("activity.json", %{activity: %{data: %{"type" => "Like"}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"]) user = get_user(activity.data["actor"], opts)
liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]) liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
created_at = created_at =
@ -154,8 +207,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
"activity.json", "activity.json",
%{activity: %{data: %{"type" => "Create", "object" => object}} = activity} = opts %{activity: %{data: %{"type" => "Create", "object" => object}} = activity} = opts
) do ) do
actor = get_in(activity.data, ["actor"]) user = get_user(activity.data["actor"], opts)
user = User.get_cached_by_ap_id(actor)
created_at = object["published"] |> Utils.date_to_asctime() created_at = object["published"] |> Utils.date_to_asctime()
like_count = object["like_count"] || 0 like_count = object["like_count"] || 0
@ -165,7 +217,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
attentions = attentions =
activity.recipients activity.recipients
|> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end) |> Enum.map(fn ap_id -> get_user(ap_id, opts) end)
|> Enum.filter(& &1) |> Enum.filter(& &1)
|> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end) |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)

View file

@ -64,7 +64,12 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
{ {
TwitterAPI, TwitterAPI,
[], [],
[context_to_conversation_id: fn(_) -> false end] [context_to_conversation_id: fn _ -> false end]
},
{
User,
[:passthrough],
[get_cached_by_ap_id: fn _ -> nil end]
} }
] ]
@ -73,7 +78,9 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
assert result["statusnet_conversation_id"] == convo_id assert result["statusnet_conversation_id"] == convo_id
assert result["user"] assert result["user"]
refute called TwitterAPI.context_to_conversation_id(:_) refute called(TwitterAPI.context_to_conversation_id(:_))
refute called(User.get_cached_by_ap_id(user.ap_id))
refute called(User.get_cached_by_ap_id(other_user.ap_id))
end end
end end