Merge branch 'feat/chat-list-pagination' into 'develop'

Chats: Introduce /api/v2/pleroma/chats which implements pagination

Closes #2140

See merge request pleroma/pleroma!3325
This commit is contained in:
Haelwenn 2021-02-17 15:36:59 +00:00
commit e7b1f0f5f4
5 changed files with 196 additions and 127 deletions

View file

@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **Breaking:** AdminAPI `GET /api/pleroma/admin/users/:nickname_or_id/statuses` changed response format and added the number of total users posts. - **Breaking:** AdminAPI `GET /api/pleroma/admin/users/:nickname_or_id/statuses` changed response format and added the number of total users posts.
- **Breaking:** AdminAPI `GET /api/pleroma/admin/instances/:instance/statuses` changed response format and added the number of total users posts. - **Breaking:** AdminAPI `GET /api/pleroma/admin/instances/:instance/statuses` changed response format and added the number of total users posts.
- Admin API: Reports now ordered by newest - Admin API: Reports now ordered by newest
- Pleroma API: `GET /api/v1/pleroma/chats` is deprecated in favor of `GET /api/v2/pleroma/chats`.
</details> </details>
@ -58,6 +59,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
<details> <details>
<summary>API Changes</summary> <summary>API Changes</summary>
- Admin API: (`GET /api/pleroma/admin/users`) filter users by `unconfirmed` status and `actor_type`. - Admin API: (`GET /api/pleroma/admin/users`) filter users by `unconfirmed` status and `actor_type`.
- Pleroma API: `GET /api/v2/pleroma/chats` added. It is exactly like `GET /api/v1/pleroma/chats` except supports pagination.
- Pleroma API: Add `idempotency_key` to the chat message entity that can be used for optimistic message sending. - Pleroma API: Add `idempotency_key` to the chat message entity that can be used for optimistic message sending.
- Pleroma API: (`GET /api/v1/pleroma/federation_status`) Add a way to get a list of unreachable instances. - Pleroma API: (`GET /api/v1/pleroma/federation_status`) Add a way to get a list of unreachable instances.
- Mastodon API: User and conversation mutes can now auto-expire if `expires_in` parameter was given while adding the mute. - Mastodon API: User and conversation mutes can now auto-expire if `expires_in` parameter was given while adding the mute.

View file

@ -131,8 +131,30 @@ def create_operation do
def index_operation do def index_operation do
%Operation{ %Operation{
tags: ["Chats"], tags: ["Chats"],
summary: "Retrieve list of chats", summary: "Retrieve list of chats (unpaginated)",
deprecated: true,
description:
"Deprecated due to no support for pagination. Using [/api/v2/pleroma/chats](#operation/ChatController.index2) instead is recommended.",
operationId: "ChatController.index", operationId: "ChatController.index",
parameters: [
Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users")
],
responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response())
},
security: [
%{
"oAuth" => ["read:chats"]
}
]
}
end
def index2_operation do
%Operation{
tags: ["Chats"],
summary: "Retrieve list of chats",
operationId: "ChatController.index2",
parameters: [ parameters: [
Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users") Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users")
| pagination_params() | pagination_params()

View file

@ -35,7 +35,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["read:chats"]} when action in [:messages, :index, :show] %{scopes: ["read:chats"]} when action in [:messages, :index, :index2, :show]
) )
plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError) plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError)
@ -138,18 +138,30 @@ def messages(%{assigns: %{user: user}} = conn, %{id: id} = params) do
end end
end end
def index(%{assigns: %{user: %{id: user_id} = user}} = conn, params) do def index(%{assigns: %{user: user}} = conn, params) do
chats =
index_query(user, params)
|> Repo.all()
render(conn, "index.json", chats: chats)
end
def index2(%{assigns: %{user: user}} = conn, params) do
chats =
index_query(user, params)
|> Pagination.fetch_paginated(params)
render(conn, "index.json", chats: chats)
end
defp index_query(%{id: user_id} = user, params) do
exclude_users = exclude_users =
User.cached_blocked_users_ap_ids(user) ++ User.cached_blocked_users_ap_ids(user) ++
if params[:with_muted], do: [], else: User.cached_muted_users_ap_ids(user) if params[:with_muted], do: [], else: User.cached_muted_users_ap_ids(user)
chats =
user_id user_id
|> Chat.for_user_query() |> Chat.for_user_query()
|> where([c], c.recipient not in ^exclude_users) |> where([c], c.recipient not in ^exclude_users)
|> Repo.all()
render(conn, "index.json", chats: chats)
end end
def create(%{assigns: %{user: user}} = conn, %{id: id}) do def create(%{assigns: %{user: user}} = conn, %{id: id}) do

View file

@ -420,6 +420,13 @@ defmodule Pleroma.Web.Router do
get("/federation_status", InstancesController, :show) get("/federation_status", InstancesController, :show)
end end
scope "/api/v2/pleroma", Pleroma.Web.PleromaAPI do
scope [] do
pipe_through(:authenticated_api)
get("/chats", ChatController, :index2)
end
end
scope "/api/v1", Pleroma.Web.MastodonAPI do scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through(:authenticated_api) pipe_through(:authenticated_api)

View file

@ -304,7 +304,8 @@ test "it returns a chat", %{conn: conn, user: user} do
end end
end end
describe "GET /api/v1/pleroma/chats" do for tested_endpoint <- ["/api/v1/pleroma/chats", "/api/v2/pleroma/chats"] do
describe "GET #{tested_endpoint}" do
setup do: oauth_access(["read:chats"]) setup do: oauth_access(["read:chats"])
test "it does not return chats with deleted users", %{conn: conn, user: user} do test "it does not return chats with deleted users", %{conn: conn, user: user} do
@ -316,7 +317,7 @@ test "it does not return chats with deleted users", %{conn: conn, user: user} do
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 0 assert length(result) == 0
@ -329,7 +330,7 @@ test "it does not return chats with users you blocked", %{conn: conn, user: user
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 1 assert length(result) == 1
@ -338,7 +339,7 @@ test "it does not return chats with users you blocked", %{conn: conn, user: user
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 0 assert length(result) == 0
@ -351,7 +352,7 @@ test "it does not return chats with users you muted", %{conn: conn, user: user}
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 1 assert length(result) == 1
@ -360,19 +361,20 @@ test "it does not return chats with users you muted", %{conn: conn, user: user}
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 0 assert length(result) == 0
result = result =
conn conn
|> get("/api/v1/pleroma/chats?with_muted=true") |> get("#{unquote(tested_endpoint)}?with_muted=true")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 1 assert length(result) == 1
end end
if tested_endpoint == "/api/v1/pleroma/chats" do
test "it returns all chats", %{conn: conn, user: user} do test "it returns all chats", %{conn: conn, user: user} do
Enum.each(1..30, fn _ -> Enum.each(1..30, fn _ ->
recipient = insert(:user) recipient = insert(:user)
@ -381,11 +383,34 @@ test "it returns all chats", %{conn: conn, user: user} do
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert length(result) == 30 assert length(result) == 30
end end
else
test "it paginates chats", %{conn: conn, user: user} do
Enum.each(1..30, fn _ ->
recipient = insert(:user)
{:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
end)
result =
conn
|> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200)
assert length(result) == 20
last_id = List.last(result)["id"]
result =
conn
|> get(unquote(tested_endpoint) <> "?max_id=#{last_id}")
|> json_response_and_validate_schema(200)
assert length(result) == 10
end
end
test "it return a list of chats the current user is participating in, in descending order of updates", test "it return a list of chats the current user is participating in, in descending order of updates",
%{conn: conn, user: user} do %{conn: conn, user: user} do
@ -405,7 +430,7 @@ test "it return a list of chats the current user is participating in, in descend
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
ids = Enum.map(result, & &1["id"]) ids = Enum.map(result, & &1["id"])
@ -432,11 +457,12 @@ test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{
result = result =
conn conn
|> get("/api/v1/pleroma/chats") |> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
account_ids = Enum.map(result, &get_in(&1, ["account", "id"])) account_ids = Enum.map(result, &get_in(&1, ["account", "id"]))
assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id]) assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id])
end end
end end
end
end end