From f4463d4adf9de594d743c69ac5c7cb8eec20c9d0 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Sun, 4 Dec 2022 15:27:48 +0000 Subject: [PATCH] Include followed hashtags in home timeline --- lib/mix/tasks/pleroma/user.ex | 7 +++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 12 ++++++++++-- .../controllers/timeline_controller.ex | 2 +- .../web/activity_pub/activity_pub_test.exs | 18 ++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 278a01acc..dd1cdca5b 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -471,9 +471,15 @@ defmodule Mix.Tasks.Pleroma.User do def run(["timeline_query", nickname]) do start_pleroma() + params = %{local: true} with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do + followed_hashtags = + user + |> User.followed_hashtags() + |> Enum.map(& &1.id) + params = params |> Map.put(:type, ["Create", "Announce"]) @@ -484,6 +490,7 @@ defmodule Mix.Tasks.Pleroma.User do |> Map.put(:announce_filtering_user, user) |> Map.put(:user, user) |> Map.put(:local_only, params[:local]) + |> Map.put(:hashtags, followed_hashtags) |> Map.delete(:local) _activities = diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a8a3188b7..8233bcbf8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -933,11 +933,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do ) end + # Essentially, either look for activities addressed to `recipients`, _OR_ ones + # 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, hashtag_ids) do + 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: hto in "hashtags_objects", @@ -1395,7 +1403,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[:hashtags]) + |> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags]) |> restrict_replies(opts) |> restrict_since(opts) |> restrict_local(opts) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index b82bb498a..2d0e36420 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -55,7 +55,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(:hashtags, followed_hashtags) + |> Map.put(:followed_hashtags, followed_hashtags) |> Map.delete(:local) activities = diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 8d39b1076..fc452ef1a 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -719,6 +719,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end end + describe "fetch activities for followed hashtags" do + test "it should return public activities that reference a given hashtag" do + hashtag = insert(:hashtag, name: "tenshi") + user = insert(:user) + + {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"}) + {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"}) + {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"}) + {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"}) + + activities = ActivityPub.fetch_activities([], %{followed_hashtags: [hashtag.id]}) + assert length(activities) == 2 + public_id = public.id + unlisted_id = unlisted.id + assert [%{id: ^public_id}, %{id: ^unlisted_id}] = activities + end + end + describe "fetch activities in context" do test "retrieves activities that have a given context" do {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})