Fix account favourites ordering

This commit is contained in:
Lain Soykaf 2026-05-25 18:09:18 +04:00
commit a84d16831f
No known key found for this signature in database
3 changed files with 90 additions and 12 deletions

View file

@ -0,0 +1 @@
Fixed `/api/v1/pleroma/accounts/:id/favourites` ordering and pagination to use the favourite date.

View file

@ -537,9 +537,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
# and extra sorting on "activities.id DESC NULLS LAST" would worse the query plan
opts = Map.put(opts, :skip_extra_order, true)
Pagination.fetch_paginated(query, opts, pagination)
Pagination.fetch_paginated(query, opts, pagination, pagination_binding(opts))
end
defp pagination_binding(%{favorited_by: _}), do: :favorited_activity
defp pagination_binding(_), do: nil
def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do
list_memberships = Pleroma.List.memberships(opts[:user])
@ -786,6 +789,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_since(query, %{since_id: ""}), do: query
defp restrict_since(query, %{favorited_by: _, since_id: _}), do: query
defp restrict_since(query, %{since_id: since_id}) do
from(activity in query, where: activity.id > ^since_id)
end
@ -1013,8 +1018,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_favorited_by(query, %{favorited_by: ap_id}) do
from(
[_activity, object] in query,
where: fragment("(?)->'likes' \\? (?)", object.data, ^ap_id)
[activity, object: object] in query,
join: favorited_activity in Activity,
as: :favorited_activity,
on:
favorited_activity.actor == ^ap_id and
fragment("?->>'type' = ?", favorited_activity.data, "Like") and
fragment("associated_object_id(?) = (?)->>'id'", favorited_activity.data, object.data),
select: %Activity{activity | pagination_id: favorited_activity.id}
)
end

View file

@ -105,6 +105,28 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
assert length(response) == 1
end
test "orders statuses by favorite date", %{
conn: conn,
user: user
} do
other_user = insert(:user)
{:ok, first_post} = CommonAPI.post(other_user, %{status: "first post"})
{:ok, second_post} = CommonAPI.post(other_user, %{status: "second post"})
{:ok, third_post} = CommonAPI.post(other_user, %{status: "third post"})
{:ok, _} = CommonAPI.favorite(third_post.id, user)
{:ok, _} = CommonAPI.favorite(first_post.id, user)
{:ok, _} = CommonAPI.favorite(second_post.id, user)
response =
conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response_and_validate_schema(:ok)
assert Enum.map(response, & &1["id"]) == [second_post.id, first_post.id, third_post.id]
end
test "returns favorited DM only when user is logged in and he is one of recipients", %{
current_user: current_user,
user: user
@ -164,23 +186,67 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
} do
activities = insert_list(10, :note_activity)
Enum.each(activities, fn activity ->
CommonAPI.favorite(activity.id, user)
end)
favorite_pairs =
Enum.map(activities, fn activity ->
{:ok, favorite} = CommonAPI.favorite(activity.id, user)
{favorite, activity}
end)
|> Enum.sort_by(fn {favorite, _activity} -> FlakeId.from_string(favorite.id) end)
third_activity = Enum.at(activities, 2)
seventh_activity = Enum.at(activities, 6)
{third_favorite, _} = Enum.at(favorite_pairs, 2)
{seventh_favorite, _} = Enum.at(favorite_pairs, 6)
expected_ids =
favorite_pairs
|> Enum.slice(3, 3)
|> Enum.reverse()
|> Enum.map(fn {_favorite, activity} -> activity.id end)
response =
conn
|> get(
"/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{seventh_activity.id}"
"/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_favorite.id}&max_id=#{seventh_favorite.id}"
)
|> json_response_and_validate_schema(:ok)
assert length(response) == 3
refute third_activity in response
refute seventh_activity in response
assert Enum.map(response, & &1["id"]) == expected_ids
end
test "paginates favorites using min_id and limit", %{
conn: conn,
user: user
} do
activities = insert_list(10, :note_activity)
favorite_pairs =
Enum.map(activities, fn activity ->
{:ok, favorite} = CommonAPI.favorite(activity.id, user)
{favorite, activity}
end)
|> Enum.sort_by(fn {favorite, _activity} -> FlakeId.from_string(favorite.id) end)
{third_favorite, _} = Enum.at(favorite_pairs, 2)
{fourth_favorite, _} = Enum.at(favorite_pairs, 3)
{fifth_favorite, _} = Enum.at(favorite_pairs, 4)
expected_ids =
favorite_pairs
|> Enum.slice(3, 2)
|> Enum.reverse()
|> Enum.map(fn {_favorite, activity} -> activity.id end)
conn =
get(
conn,
"/api/v1/pleroma/accounts/#{user.id}/favourites?min_id=#{third_favorite.id}&limit=2"
)
response = json_response_and_validate_schema(conn, :ok)
assert Enum.map(response, & &1["id"]) == expected_ids
assert [link_header] = get_resp_header(conn, "link")
assert link_header =~ "max_id=#{fourth_favorite.id}"
assert link_header =~ "min_id=#{fifth_favorite.id}"
end
test "limits favorites using limit parameter", %{