Optimize followed hashtag ids query, add test for hashtags in home timeline

Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
mkljczk 2025-03-01 19:28:23 +01:00
parent 16944eb9da
commit 0354ff06d8
4 changed files with 36 additions and 16 deletions

View file

@ -0,0 +1 @@
Optimize followed hashtag ids query, add test for hashtags in home timeline

View file

@ -928,15 +928,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
# that reference a hashtag that the user follows
# Firstly, two fallbacks in case there's no hashtag constraint, or the user doesn't
# follow any
defp restrict_recipients_or_hashtags(query, recipients, user, nil) do
restrict_recipients(query, recipients, user)
end
defp restrict_recipients_or_hashtags(query, recipients, user, true) do
followed_hashtag_ids = Ecto.assoc(user, :followed_hashtags) |> select([h], h.id)
defp restrict_recipients_or_hashtags(query, recipients, user, []) do
restrict_recipients(query, recipients, user)
end
defp restrict_recipients_or_hashtags(query, recipients, _user, hashtag_ids) do
from([activity, object] in query)
|> join(:left, [activity, object], hto in "hashtags_objects",
on: hto.object_id == object.id,
@ -944,11 +938,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
)
|> where(
[activity, object, hto: hto],
(hto.hashtag_id in ^hashtag_ids and ^Constants.as_public() in activity.recipients) or
(hto.hashtag_id in subquery(followed_hashtag_ids) and
^Constants.as_public() in activity.recipients) or
fragment("? && ?", ^recipients, activity.recipients)
)
end
defp restrict_recipients_or_hashtags(query, recipients, user, _) do
restrict_recipients(query, recipients, user)
end
defp restrict_local(query, %{local_only: true}) do
from(activity in query, where: activity.local == true)
end
@ -1439,7 +1438,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> maybe_preload_report_notes(opts)
|> maybe_set_thread_muted_field(opts)
|> maybe_order(opts)
|> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags])
|> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:with_followed_hashtags])
|> restrict_replies(opts)
|> restrict_since(opts)
|> restrict_local(opts)

View file

@ -40,11 +40,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
# GET /api/v1/timelines/home
def home(%{assigns: %{user: user}} = conn, params) do
followed_hashtags =
user
|> User.followed_hashtags()
|> Enum.map(& &1.id)
params =
params
|> Map.put(:type, ["Create", "Announce"])
@ -54,7 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put(:announce_filtering_user, user)
|> Map.put(:user, user)
|> Map.put(:local_only, params[:local])
|> Map.put(:followed_hashtags, followed_hashtags)
|> Map.put(:with_followed_hashtags, true)
|> Map.delete(:local)
activities =

View file

@ -149,6 +149,31 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
|> get("/api/v1/timelines/home?remote=true&local=true")
|> json_response_and_validate_schema(200) == []
end
test "includes followed hashtags", %{conn: conn, user: user} do
hashtag = insert(:hashtag, %{name: "tenshi"})
other_user = insert(:user)
{:ok, user} = User.follow_hashtag(user, hashtag)
{:ok, _} = CommonAPI.post(other_user, %{status: "hey #tenshi"})
{:ok, _} = CommonAPI.post(other_user, %{status: "hey #anotherhashtag"})
result =
conn
|> assign(:user, user)
|> get("/api/v1/timelines/home")
|> json_response_and_validate_schema(200)
assert [
%{
"tags" => [
%{
"name" => "tenshi"
}
]
}
] = result
end
end
describe "public" do