Don't fetch anything except ap_id for follower / following

collections.

Should speed up the queries because ecto doesn't have to parse the json.
This commit is contained in:
lain 2018-03-31 20:02:09 +02:00
parent 57b24b2cba
commit 2222e5599c
3 changed files with 119 additions and 19 deletions

View file

@ -278,24 +278,30 @@ defmodule Pleroma.User do
end end
end end
def get_followers(%User{id: id, follower_address: follower_address}) do def get_followers_query(%User{id: id, follower_address: follower_address}) do
q =
from( from(
u in User, u in User,
where: fragment("? <@ ?", ^[follower_address], u.following), where: fragment("? <@ ?", ^[follower_address], u.following),
where: u.id != ^id where: u.id != ^id
) )
end
def get_followers(user) do
q = get_followers_query(user)
{:ok, Repo.all(q)} {:ok, Repo.all(q)}
end end
def get_friends(%User{id: id, following: following}) do def get_friends_query(%User{id: id, following: following}) do
q =
from( from(
u in User, u in User,
where: u.follower_address in ^following, where: u.follower_address in ^following,
where: u.id != ^id where: u.id != ^id
) )
end
def get_friends(user) do
q = get_friends_query(user)
{:ok, Repo.all(q)} {:ok, Repo.all(q)}
end end

View file

@ -3,9 +3,11 @@ defmodule Pleroma.Web.ActivityPub.UserView do
alias Pleroma.Web.Salmon alias Pleroma.Web.Salmon
alias Pleroma.Web.WebFinger alias Pleroma.Web.WebFinger
alias Pleroma.User alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
import Ecto.Query
def render("user.json", %{user: user}) do def render("user.json", %{user: user}) do
{:ok, user} = WebFinger.ensure_keys_present(user) {:ok, user} = WebFinger.ensure_keys_present(user)
@ -45,10 +47,11 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|> Map.merge(Utils.make_json_ld_header()) |> Map.merge(Utils.make_json_ld_header())
end end
def collection(collection, iri, page) do def collection(collection, iri, page, total \\ nil) do
offset = (page - 1) * 10 offset = (page - 1) * 10
items = Enum.slice(collection, offset, 10) items = Enum.slice(collection, offset, 10)
items = Enum.map(items, fn user -> user.ap_id end) items = Enum.map(items, fn user -> user.ap_id end)
total = total || length(collection)
map = %{ map = %{
"id" => "#{iri}?page=#{page}", "id" => "#{iri}?page=#{page}",
@ -64,14 +67,18 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end end
def render("following.json", %{user: user, page: page}) do def render("following.json", %{user: user, page: page}) do
{:ok, following} = User.get_friends(user) query = User.get_friends_query(user)
query = from(user in query, select: [:ap_id])
following = Repo.all(query)
collection(following, "#{user.ap_id}/following", page) collection(following, "#{user.ap_id}/following", page)
|> Map.merge(Utils.make_json_ld_header()) |> Map.merge(Utils.make_json_ld_header())
end end
def render("following.json", %{user: user}) do def render("following.json", %{user: user}) do
{:ok, following} = User.get_friends(user) query = User.get_friends_query(user)
query = from(user in query, select: [:ap_id])
following = Repo.all(query)
%{ %{
"id" => "#{user.ap_id}/following", "id" => "#{user.ap_id}/following",
@ -83,14 +90,18 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end end
def render("followers.json", %{user: user, page: page}) do def render("followers.json", %{user: user, page: page}) do
{:ok, followers} = User.get_followers(user) query = User.get_followers_query(user)
query = from(user in query, select: [:ap_id])
followers = Repo.all(query)
collection(followers, "#{user.ap_id}/followers", page) collection(followers, "#{user.ap_id}/followers", page)
|> Map.merge(Utils.make_json_ld_header()) |> Map.merge(Utils.make_json_ld_header())
end end
def render("followers.json", %{user: user}) do def render("followers.json", %{user: user}) do
{:ok, followers} = User.get_followers(user) query = User.get_followers_query(user)
query = from(user in query, select: [:ap_id])
followers = Repo.all(query)
%{ %{
"id" => "#{user.ap_id}/followers", "id" => "#{user.ap_id}/followers",

View file

@ -49,4 +49,87 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert Activity.get_by_ap_id(data["id"]) assert Activity.get_by_ap_id(data["id"])
end end
end end
describe "/users/:nickname/followers" do
test "it returns the followers in a collection", %{conn: conn} do
user = insert(:user)
user_two = insert(:user)
User.follow(user, user_two)
result =
conn
|> get("/users/#{user_two.nickname}/followers")
|> json_response(200)
assert result["first"]["orderedItems"] == [user.ap_id]
end
test "it works for more than 10 users", %{conn: conn} do
user = insert(:user)
Enum.each(1..15, fn _ ->
other_user = insert(:user)
User.follow(other_user, user)
end)
result =
conn
|> get("/users/#{user.nickname}/followers")
|> json_response(200)
assert length(result["first"]["orderedItems"]) == 10
assert result["first"]["totalItems"] == 15
assert result["totalItems"] == 15
result =
conn
|> get("/users/#{user.nickname}/followers?page=2")
|> json_response(200)
assert length(result["orderedItems"]) == 5
assert result["totalItems"] == 15
end
end
describe "/users/:nickname/following" do
test "it returns the following in a collection", %{conn: conn} do
user = insert(:user)
user_two = insert(:user)
User.follow(user, user_two)
result =
conn
|> get("/users/#{user.nickname}/following")
|> json_response(200)
assert result["first"]["orderedItems"] == [user_two.ap_id]
end
test "it works for more than 10 users", %{conn: conn} do
user = insert(:user)
Enum.each(1..15, fn _ ->
user = Repo.get(User, user.id)
other_user = insert(:user)
User.follow(user, other_user)
end)
result =
conn
|> get("/users/#{user.nickname}/following")
|> json_response(200)
assert length(result["first"]["orderedItems"]) == 10
assert result["first"]["totalItems"] == 15
assert result["totalItems"] == 15
result =
conn
|> get("/users/#{user.nickname}/following?page=2")
|> json_response(200)
assert length(result["orderedItems"]) == 5
assert result["totalItems"] == 15
end
end
end end