Load all users at once in timelines.
This commit is contained in:
parent
96007753ad
commit
b3b7ab5d9a
|
@ -50,10 +50,13 @@ def create_context(context) 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
|
||||||
|
|
||||||
|
|
|
@ -513,7 +513,9 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) 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)
|
||||||
|
|
|
@ -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 @@ def render("index.json", opts) 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 @@ def render("activity.json", %{activity: %{data: %{"type" => "Delete"}} = activit
|
||||||
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 @@ def render("activity.json", %{activity: %{data: %{"type" => "Follow"}} = activit
|
||||||
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 @@ def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activ
|
||||||
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 @@ def render(
|
||||||
"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 @@ def render(
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,12 @@ test "a list of activities" 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 @@ test "a list of activities" 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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue