MastoAPI followers/following endpoints

This commit is contained in:
eugenijm 2019-03-11 21:03:30 +03:00
parent 2c8deecdd2
commit 984b5f8adf
3 changed files with 151 additions and 4 deletions

View file

@ -1 +1,63 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
import Ecto.Query
import Ecto.Changeset
alias Pleroma.User
alias Pleroma.Repo
@default_limit 20
def get_followers(user, params \\ %{}) do
user
|> User.get_followers_query()
|> paginate(params)
|> Repo.all()
end
def get_friends(user, params \\ %{}) do
user
|> User.get_friends_query()
|> paginate(params)
|> Repo.all()
end
def paginate(query, params \\ %{}) do
options = cast_params(params)
query
|> restrict(:max_id, options)
|> restrict(:since_id, options)
|> restrict(:limit, options)
|> order_by([u], fragment("? desc nulls last", u.id))
end
def cast_params(params) do
param_types = %{
max_id: :string,
since_id: :string,
limit: :integer
}
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
changeset.changes
end
defp restrict(query, :max_id, %{max_id: max_id}) do
query
|> where([q], q.id < ^max_id)
end
defp restrict(query, :since_id, %{since_id: since_id}) do
query
|> where([q], q.id > ^since_id)
end
defp restrict(query, :limit, options) do
limit = Map.get(options, :limit, @default_limit)
query
|> limit(^limit)
end
defp restrict(query, _, _), do: query
end

View file

@ -22,6 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web.MastodonAPI.MastodonView alias Pleroma.Web.MastodonAPI.MastodonView
alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MastodonAPI.ReportView alias Pleroma.Web.MastodonAPI.ReportView
alias Pleroma.Web.MastodonAPI.MastodonAPI
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
@ -652,9 +653,9 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do
|> render("index.json", %{activities: activities, for: user, as: :activity}) |> render("index.json", %{activities: activities, for: user, as: :activity})
end end
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
with %User{} = user <- Repo.get(User, id), with %User{} = user <- Repo.get(User, id),
{:ok, followers} <- User.get_followers(user) do followers <- MastodonAPI.get_followers(user, params) do
followers = followers =
cond do cond do
for_user && user.id == for_user.id -> followers for_user && user.id == for_user.id -> followers
@ -663,14 +664,15 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
end end
conn conn
|> add_link_headers(:followers, followers, user)
|> put_view(AccountView) |> put_view(AccountView)
|> render("accounts.json", %{users: followers, as: :user}) |> render("accounts.json", %{users: followers, as: :user})
end end
end end
def following(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
with %User{} = user <- Repo.get(User, id), with %User{} = user <- Repo.get(User, id),
{:ok, followers} <- User.get_friends(user) do followers <- MastodonAPI.get_friends(user, params) do
followers = followers =
cond do cond do
for_user && user.id == for_user.id -> followers for_user && user.id == for_user.id -> followers
@ -679,6 +681,7 @@ def following(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
end end
conn conn
|> add_link_headers(:following, followers, user)
|> put_view(AccountView) |> put_view(AccountView)
|> render("accounts.json", %{users: followers, as: :user}) |> render("accounts.json", %{users: followers, as: :user})
end end

View file

@ -1184,6 +1184,47 @@ test "getting followers, hide_followers, same user requesting", %{conn: conn} do
refute [] == json_response(conn, 200) refute [] == json_response(conn, 200)
end end
test "getting followers, pagination", %{conn: conn} do
user = insert(:user)
follower1 = insert(:user)
follower2 = insert(:user)
follower3 = insert(:user)
{:ok, _} = User.follow(follower1, user)
{:ok, _} = User.follow(follower2, user)
{:ok, _} = User.follow(follower3, user)
conn =
conn
|> assign(:user, user)
res_conn =
conn
|> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
assert id3 == follower3.id
assert id2 == follower2.id
res_conn =
conn
|> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
assert id2 == follower2.id
assert id1 == follower1.id
res_conn =
conn
|> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
assert [%{"id" => id2}] = json_response(res_conn, 200)
assert id2 == follower2.id
assert [link_header] = get_resp_header(res_conn, "link")
assert link_header =~ ~r/since_id=#{follower2.id}/
assert link_header =~ ~r/max_id=#{follower2.id}/
end
test "getting following", %{conn: conn} do test "getting following", %{conn: conn} do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
@ -1222,6 +1263,47 @@ test "getting following, hide_follows, same user requesting", %{conn: conn} do
refute [] == json_response(conn, 200) refute [] == json_response(conn, 200)
end end
test "getting following, pagination", %{conn: conn} do
user = insert(:user)
following1 = insert(:user)
following2 = insert(:user)
following3 = insert(:user)
{:ok, _} = User.follow(user, following1)
{:ok, _} = User.follow(user, following2)
{:ok, _} = User.follow(user, following3)
conn =
conn
|> assign(:user, user)
res_conn =
conn
|> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
assert id3 == following3.id
assert id2 == following2.id
res_conn =
conn
|> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
assert id2 == following2.id
assert id1 == following1.id
res_conn =
conn
|> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
assert [%{"id" => id2}] = json_response(res_conn, 200)
assert id2 == following2.id
assert [link_header] = get_resp_header(res_conn, "link")
assert link_header =~ ~r/since_id=#{following2.id}/
assert link_header =~ ~r/max_id=#{following2.id}/
end
test "following / unfollowing a user", %{conn: conn} do test "following / unfollowing a user", %{conn: conn} do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)